License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 14:07:57 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifndef _LINUX_PAGEMAP_H
|
|
|
|
#define _LINUX_PAGEMAP_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright 1995 Linus Torvalds
|
|
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/highmem.h>
|
|
|
|
#include <linux/compiler.h>
|
2016-12-24 19:46:01 +00:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/gfp.h>
|
2007-05-08 07:23:25 +00:00
|
|
|
#include <linux/bitops.h>
|
2008-07-26 02:45:30 +00:00
|
|
|
#include <linux/hardirq.h> /* for in_interrupt() */
|
2010-05-28 00:29:15 +00:00
|
|
|
#include <linux/hugetlb_inline.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2021-12-07 19:15:07 +00:00
|
|
|
struct folio_batch;
|
2017-11-16 01:37:33 +00:00
|
|
|
|
2022-02-13 22:23:58 +00:00
|
|
|
unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|
|
|
pgoff_t start, pgoff_t end);
|
|
|
|
|
|
|
|
static inline void invalidate_remote_inode(struct inode *inode)
|
|
|
|
{
|
|
|
|
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
|
|
|
S_ISLNK(inode->i_mode))
|
|
|
|
invalidate_mapping_pages(inode->i_mapping, 0, -1);
|
|
|
|
}
|
|
|
|
int invalidate_inode_pages2(struct address_space *mapping);
|
|
|
|
int invalidate_inode_pages2_range(struct address_space *mapping,
|
|
|
|
pgoff_t start, pgoff_t end);
|
2023-06-01 14:58:57 +00:00
|
|
|
int kiocb_invalidate_pages(struct kiocb *iocb, size_t count);
|
2023-06-01 14:58:58 +00:00
|
|
|
void kiocb_invalidate_post_direct_write(struct kiocb *iocb, size_t count);
|
2024-09-11 16:34:39 +00:00
|
|
|
int filemap_invalidate_pages(struct address_space *mapping,
|
|
|
|
loff_t pos, loff_t end, bool nowait);
|
2023-06-01 14:58:56 +00:00
|
|
|
|
2022-02-13 22:23:58 +00:00
|
|
|
int write_inode_now(struct inode *, int sync);
|
|
|
|
int filemap_fdatawrite(struct address_space *);
|
|
|
|
int filemap_flush(struct address_space *);
|
|
|
|
int filemap_fdatawait_keep_errors(struct address_space *mapping);
|
|
|
|
int filemap_fdatawait_range(struct address_space *, loff_t lstart, loff_t lend);
|
|
|
|
int filemap_fdatawait_range_keep_errors(struct address_space *mapping,
|
|
|
|
loff_t start_byte, loff_t end_byte);
|
mm: Provide a means of invalidation without using launder_folio
Implement a replacement for launder_folio. The key feature of
invalidate_inode_pages2() is that it locks each folio individually, unmaps
it to prevent mmap'd accesses interfering and calls the ->launder_folio()
address_space op to flush it. This has problems: firstly, each folio is
written individually as one or more small writes; secondly, adjacent folios
cannot be added so easily into the laundry; thirdly, it's yet another op to
implement.
Instead, use the invalidate lock to cause anyone wanting to add a folio to
the inode to wait, then unmap all the folios if we have mmaps, then,
conditionally, use ->writepages() to flush any dirty data back and then
discard all pages.
The invalidate lock prevents ->read_iter(), ->write_iter() and faulting
through mmap all from adding pages for the duration.
This is then used from netfslib to handle the flusing in unbuffered and
direct writes.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Matthew Wilcox <willy@infradead.org>
cc: Miklos Szeredi <miklos@szeredi.hu>
cc: Trond Myklebust <trond.myklebust@hammerspace.com>
cc: Christoph Hellwig <hch@lst.de>
cc: Andrew Morton <akpm@linux-foundation.org>
cc: Alexander Viro <viro@zeniv.linux.org.uk>
cc: Christian Brauner <brauner@kernel.org>
cc: Jeff Layton <jlayton@kernel.org>
cc: linux-mm@kvack.org
cc: linux-fsdevel@vger.kernel.org
cc: netfs@lists.linux.dev
cc: v9fs@lists.linux.dev
cc: linux-afs@lists.infradead.org
cc: ceph-devel@vger.kernel.org
cc: linux-cifs@vger.kernel.org
cc: linux-nfs@vger.kernel.org
cc: devel@lists.orangefs.org
2024-03-27 08:51:38 +00:00
|
|
|
int filemap_invalidate_inode(struct inode *inode, bool flush,
|
|
|
|
loff_t start, loff_t end);
|
2022-02-13 22:23:58 +00:00
|
|
|
|
|
|
|
static inline int filemap_fdatawait(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return filemap_fdatawait_range(mapping, 0, LLONG_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool filemap_range_has_page(struct address_space *, loff_t lstart, loff_t lend);
|
|
|
|
int filemap_write_and_wait_range(struct address_space *mapping,
|
|
|
|
loff_t lstart, loff_t lend);
|
|
|
|
int __filemap_fdatawrite_range(struct address_space *mapping,
|
|
|
|
loff_t start, loff_t end, int sync_mode);
|
|
|
|
int filemap_fdatawrite_range(struct address_space *mapping,
|
|
|
|
loff_t start, loff_t end);
|
|
|
|
int filemap_check_errors(struct address_space *mapping);
|
|
|
|
void __filemap_set_wb_err(struct address_space *mapping, int err);
|
|
|
|
int filemap_fdatawrite_wbc(struct address_space *mapping,
|
|
|
|
struct writeback_control *wbc);
|
2023-06-01 14:58:56 +00:00
|
|
|
int kiocb_write_and_wait(struct kiocb *iocb, size_t count);
|
2022-02-13 22:23:58 +00:00
|
|
|
|
|
|
|
static inline int filemap_write_and_wait(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return filemap_write_and_wait_range(mapping, 0, LLONG_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_set_wb_err - set a writeback error on an address_space
|
|
|
|
* @mapping: mapping in which to set writeback error
|
|
|
|
* @err: error to be set in mapping
|
|
|
|
*
|
|
|
|
* When writeback fails in some way, we must record that error so that
|
|
|
|
* userspace can be informed when fsync and the like are called. We endeavor
|
|
|
|
* to report errors on any file that was open at the time of the error. Some
|
|
|
|
* internal callers also need to know when writeback errors have occurred.
|
|
|
|
*
|
|
|
|
* When a writeback error occurs, most filesystems will want to call
|
|
|
|
* filemap_set_wb_err to record the error in the mapping so that it will be
|
|
|
|
* automatically reported whenever fsync is called on the file.
|
|
|
|
*/
|
|
|
|
static inline void filemap_set_wb_err(struct address_space *mapping, int err)
|
|
|
|
{
|
|
|
|
/* Fastpath for common case of no error */
|
|
|
|
if (unlikely(err))
|
|
|
|
__filemap_set_wb_err(mapping, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_check_wb_err - has an error occurred since the mark was sampled?
|
|
|
|
* @mapping: mapping to check for writeback errors
|
|
|
|
* @since: previously-sampled errseq_t
|
|
|
|
*
|
|
|
|
* Grab the errseq_t value from the mapping, and see if it has changed "since"
|
|
|
|
* the given value was sampled.
|
|
|
|
*
|
|
|
|
* If it has then report the latest error set, otherwise return 0.
|
|
|
|
*/
|
|
|
|
static inline int filemap_check_wb_err(struct address_space *mapping,
|
|
|
|
errseq_t since)
|
|
|
|
{
|
|
|
|
return errseq_check(&mapping->wb_err, since);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_sample_wb_err - sample the current errseq_t to test for later errors
|
|
|
|
* @mapping: mapping to be sampled
|
|
|
|
*
|
|
|
|
* Writeback errors are always reported relative to a particular sample point
|
|
|
|
* in the past. This function provides those sample points.
|
|
|
|
*/
|
|
|
|
static inline errseq_t filemap_sample_wb_err(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return errseq_sample(&mapping->wb_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* file_sample_sb_err - sample the current errseq_t to test for later errors
|
|
|
|
* @file: file pointer to be sampled
|
|
|
|
*
|
|
|
|
* Grab the most current superblock-level errseq_t value for the given
|
|
|
|
* struct file.
|
|
|
|
*/
|
|
|
|
static inline errseq_t file_sample_sb_err(struct file *file)
|
|
|
|
{
|
|
|
|
return errseq_sample(&file->f_path.dentry->d_sb->s_wb_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush file data before changing attributes. Caller must hold any locks
|
|
|
|
* required to prevent further writes to this file until we're done setting
|
|
|
|
* flags.
|
|
|
|
*/
|
|
|
|
static inline int inode_drain_writes(struct inode *inode)
|
|
|
|
{
|
|
|
|
inode_dio_wait(inode);
|
|
|
|
return filemap_write_and_wait(inode->i_mapping);
|
|
|
|
}
|
|
|
|
|
2021-05-05 01:32:45 +00:00
|
|
|
static inline bool mapping_empty(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return xa_empty(&mapping->i_pages);
|
|
|
|
}
|
|
|
|
|
vfs: keep inodes with page cache off the inode shrinker LRU
Historically (pre-2.5), the inode shrinker used to reclaim only empty
inodes and skip over those that still contained page cache. This caused
problems on highmem hosts: struct inode could put fill lowmem zones
before the cache was getting reclaimed in the highmem zones.
To address this, the inode shrinker started to strip page cache to
facilitate reclaiming lowmem. However, this comes with its own set of
problems: the shrinkers may drop actively used page cache just because
the inodes are not currently open or dirty - think working with a large
git tree. It further doesn't respect cgroup memory protection settings
and can cause priority inversions between containers.
Nowadays, the page cache also holds non-resident info for evicted cache
pages in order to detect refaults. We've come to rely heavily on this
data inside reclaim for protecting the cache workingset and driving swap
behavior. We also use it to quantify and report workload health through
psi. The latter in turn is used for fleet health monitoring, as well as
driving automated memory sizing of workloads and containers, proactive
reclaim and memory offloading schemes.
The consequences of dropping page cache prematurely is that we're seeing
subtle and not-so-subtle failures in all of the above-mentioned
scenarios, with the workload generally entering unexpected thrashing
states while losing the ability to reliably detect it.
To fix this on non-highmem systems at least, going back to rotating
inodes on the LRU isn't feasible. We've tried (commit a76cf1a474d7
("mm: don't reclaim inodes with many attached pages")) and failed
(commit 69056ee6a8a3 ("Revert "mm: don't reclaim inodes with many
attached pages"")).
The issue is mostly that shrinker pools attract pressure based on their
size, and when objects get skipped the shrinkers remember this as
deferred reclaim work. This accumulates excessive pressure on the
remaining inodes, and we can quickly eat into heavily used ones, or
dirty ones that require IO to reclaim, when there potentially is plenty
of cold, clean cache around still.
Instead, this patch keeps populated inodes off the inode LRU in the
first place - just like an open file or dirty state would. An otherwise
clean and unused inode then gets queued when the last cache entry
disappears. This solves the problem without reintroducing the reclaim
issues, and generally is a bit more scalable than having to wade through
potentially hundreds of thousands of busy inodes.
Locking is a bit tricky because the locks protecting the inode state
(i_lock) and the inode LRU (lru_list.lock) don't nest inside the
irq-safe page cache lock (i_pages.xa_lock). Page cache deletions are
serialized through i_lock, taken before the i_pages lock, to make sure
depopulated inodes are queued reliably. Additions may race with
deletions, but we'll check again in the shrinker. If additions race
with the shrinker itself, we're protected by the i_lock: if find_inode()
or iput() win, the shrinker will bail on the elevated i_count or
I_REFERENCED; if the shrinker wins and goes ahead with the inode, it
will set I_FREEING and inhibit further igets(), which will cause the
other side to create a new instance of the inode instead.
Link: https://lkml.kernel.org/r/20210614211904.14420-4-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Roman Gushchin <guro@fb.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-11-09 02:31:24 +00:00
|
|
|
/*
|
|
|
|
* mapping_shrinkable - test if page cache state allows inode reclaim
|
|
|
|
* @mapping: the page cache mapping
|
|
|
|
*
|
|
|
|
* This checks the mapping's cache state for the pupose of inode
|
|
|
|
* reclaim and LRU management.
|
|
|
|
*
|
|
|
|
* The caller is expected to hold the i_lock, but is not required to
|
|
|
|
* hold the i_pages lock, which usually protects cache state. That's
|
|
|
|
* because the i_lock and the list_lru lock that protect the inode and
|
|
|
|
* its LRU state don't nest inside the irq-safe i_pages lock.
|
|
|
|
*
|
|
|
|
* Cache deletions are performed under the i_lock, which ensures that
|
|
|
|
* when an inode goes empty, it will reliably get queued on the LRU.
|
|
|
|
*
|
|
|
|
* Cache additions do not acquire the i_lock and may race with this
|
|
|
|
* check, in which case we'll report the inode as shrinkable when it
|
|
|
|
* has cache pages. This is okay: the shrinker also checks the
|
|
|
|
* refcount and the referenced bit, which will be elevated or set in
|
|
|
|
* the process of adding new cache pages to an inode.
|
|
|
|
*/
|
|
|
|
static inline bool mapping_shrinkable(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
void *head;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On highmem systems, there could be lowmem pressure from the
|
|
|
|
* inodes before there is highmem pressure from the page
|
|
|
|
* cache. Make inodes shrinkable regardless of cache state.
|
|
|
|
*/
|
|
|
|
if (IS_ENABLED(CONFIG_HIGHMEM))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* Cache completely empty? Shrink away. */
|
|
|
|
head = rcu_access_pointer(mapping->i_pages.xa_head);
|
|
|
|
if (!head)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The xarray stores single offset-0 entries directly in the
|
|
|
|
* head pointer, which allows non-resident page cache entries
|
|
|
|
* to escape the shadow shrinker's list of xarray nodes. The
|
|
|
|
* inode shrinker needs to pick them up under memory pressure.
|
|
|
|
*/
|
|
|
|
if (!xa_is_node(head) && xa_is_value(head))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2016-10-11 20:56:04 +00:00
|
|
|
* Bits in mapping->flags.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-04-02 23:56:45 +00:00
|
|
|
enum mapping_flags {
|
2016-10-11 20:56:04 +00:00
|
|
|
AS_EIO = 0, /* IO error on async write */
|
|
|
|
AS_ENOSPC = 1, /* ENOSPC on async write */
|
|
|
|
AS_MM_ALL_LOCKS = 2, /* under mm_take_all_locks() */
|
|
|
|
AS_UNEVICTABLE = 3, /* e.g., ramdisk, SHM_LOCK */
|
|
|
|
AS_EXITING = 4, /* final truncate in progress */
|
mm: don't use radix tree writeback tags for pages in swap cache
File pages use a set of radix tree tags (DIRTY, TOWRITE, WRITEBACK,
etc.) to accelerate finding the pages with a specific tag in the radix
tree during inode writeback. But for anonymous pages in the swap cache,
there is no inode writeback. So there is no need to find the pages with
some writeback tags in the radix tree. It is not necessary to touch
radix tree writeback tags for pages in the swap cache.
Per Rik van Riel's suggestion, a new flag AS_NO_WRITEBACK_TAGS is
introduced for address spaces which don't need to update the writeback
tags. The flag is set for swap caches. It may be used for DAX file
systems, etc.
With this patch, the swap out bandwidth improved 22.3% (from ~1.2GB/s to
~1.48GBps) in the vm-scalability swap-w-seq test case with 8 processes.
The test is done on a Xeon E5 v3 system. The swap device used is a RAM
simulated PMEM (persistent memory) device. The improvement comes from
the reduced contention on the swap cache radix tree lock. To test
sequential swapping out, the test case uses 8 processes, which
sequentially allocate and write to the anonymous pages until RAM and
part of the swap device is used up.
Details of comparison is as follow,
base base+patch
---------------- --------------------------
%stddev %change %stddev
\ | \
2506952 ± 2% +28.1% 3212076 ± 7% vm-scalability.throughput
1207402 ± 7% +22.3% 1476578 ± 6% vmstat.swap.so
10.86 ± 12% -23.4% 8.31 ± 16% perf-profile.cycles-pp._raw_spin_lock_irq.__add_to_swap_cache.add_to_swap_cache.add_to_swap.shrink_page_list
10.82 ± 13% -33.1% 7.24 ± 14% perf-profile.cycles-pp._raw_spin_lock_irqsave.__remove_mapping.shrink_page_list.shrink_inactive_list.shrink_zone_memcg
10.36 ± 11% -100.0% 0.00 ± -1% perf-profile.cycles-pp._raw_spin_lock_irqsave.__test_set_page_writeback.bdev_write_page.__swap_writepage.swap_writepage
10.52 ± 12% -100.0% 0.00 ± -1% perf-profile.cycles-pp._raw_spin_lock_irqsave.test_clear_page_writeback.end_page_writeback.page_endio.pmem_rw_page
Link: http://lkml.kernel.org/r/1472578089-5560-1-git-send-email-ying.huang@intel.com
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Shaohua Li <shli@kernel.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Tejun Heo <tj@kernel.org>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-07 23:59:30 +00:00
|
|
|
/* writeback related tags are not used */
|
2016-10-11 20:56:04 +00:00
|
|
|
AS_NO_WRITEBACK_TAGS = 5,
|
2024-08-22 13:50:09 +00:00
|
|
|
AS_RELEASE_ALWAYS = 6, /* Call ->release_folio(), even if no private data */
|
|
|
|
AS_STABLE_WRITES = 7, /* must wait for writeback before modifying
|
2023-10-25 14:10:17 +00:00
|
|
|
folio contents */
|
2024-08-22 13:50:09 +00:00
|
|
|
AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */
|
mm: add AS_WRITEBACK_INDETERMINATE mapping flag
Patch series "fuse: remove temp page copies in writeback", v6.
The purpose of this patchset is to help make writeback-cache write
performance in FUSE filesystems as fast as possible.
In the current FUSE writeback design (see commit 3be5a52b30aa ("fuse:
support writable mmap"))), a temp page is allocated for every dirty page
to be written back, the contents of the dirty page are copied over to the
temp page, and the temp page gets handed to the server to write back.
This is done so that writeback may be immediately cleared on the dirty
page, and this in turn is done for two reasons:
a) in order to mitigate the following deadlock scenario that may arise
if reclaim waits on writeback on the dirty page to complete (more
details can be found in this thread [1]):
* single-threaded FUSE server is in the middle of handling a request
that needs a memory allocation
* memory allocation triggers direct reclaim
* direct reclaim waits on a folio under writeback
* the FUSE server can't write back the folio since it's stuck in
direct reclaim
b) in order to unblock internal (eg sync, page compaction) waits on
writeback without needing the server to complete writing back to disk,
which may take an indeterminate amount of time.
Allocating and copying dirty pages to temp pages is the biggest
performance bottleneck for FUSE writeback. This patchset aims to get rid
of the temp page altogether (which will also allow us to get rid of the
internal FUSE rb tree that is needed to keep track of writeback status on
the temp pages). Benchmarks show approximately a 20% improvement in
throughput for 4k block-size writes and a 45% improvement for 1M
block-size writes.
With removing the temp page, writeback state is now only cleared on the
dirty page after the server has written it back to disk. This may take an
indeterminate amount of time. As well, there is also the possibility of
malicious or well-intentioned but buggy servers where writeback may in the
worst case scenario, never complete. This means that any
folio_wait_writeback() on a dirty page belonging to a FUSE filesystem
needs to be carefully audited.
In particular, these are the cases that need to be accounted for:
* potentially deadlocking in reclaim, as mentioned above
* potentially stalling sync(2)
* potentially stalling page migration / compaction
This patchset adds a new mapping flag, AS_WRITEBACK_INDETERMINATE, which
filesystems may set on its inode mappings to indicate that writeback
operations may take an indeterminate amount of time to complete. FUSE
will set this flag on its mappings. This patchset adds checks to the
critical parts of reclaim, sync, and page migration logic where writeback
may be waited on.
Please note the following:
* For sync(2), waiting on writeback will be skipped for FUSE, but this has no
effect on existing behavior. Dirty FUSE pages are already not guaranteed to
be written to disk by the time sync(2) returns (eg writeback is cleared on
the dirty page but the server may not have written out the temp page to disk
yet). If the caller wishes to ensure the data has actually been synced to
disk, they should use fsync(2)/fdatasync(2) instead.
* AS_WRITEBACK_INDETERMINATE does not indicate that the folios should never be
waited on when in writeback. There are some cases where the wait is
desirable. For example, for the sync_file_range() syscall, it is fine to
wait on the writeback since the caller passes in a fd for the operation.
[1] https://lore.kernel.org/linux-kernel/495d2400-1d96-4924-99d3-8b2952e05fc3@linux.alibaba.com/
This patch (of 5):
Add a new mapping flag AS_WRITEBACK_INDETERMINATE which filesystems may
set to indicate that writing back to disk may take an indeterminate amount
of time to complete. Extra caution should be taken when waiting on
writeback for folios belonging to mappings where this flag is set.
Link: https://lkml.kernel.org/r/20241122232359.429647-1-joannelkoong@gmail.com
Link: https://lkml.kernel.org/r/20241122232359.429647-2-joannelkoong@gmail.com
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: Bernd Schubert <bernd.schubert@fastmail.fm>
Cc: Jingbo Xu <jefflexu@linux.alibaba.com>
Cc: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-22 23:23:55 +00:00
|
|
|
AS_WRITEBACK_INDETERMINATE = 9, /* Use caution when waiting on writeback */
|
2024-08-22 13:50:09 +00:00
|
|
|
/* Bits 16-25 are used for FOLIO_ORDER */
|
|
|
|
AS_FOLIO_ORDER_BITS = 5,
|
|
|
|
AS_FOLIO_ORDER_MIN = 16,
|
|
|
|
AS_FOLIO_ORDER_MAX = AS_FOLIO_ORDER_MIN + AS_FOLIO_ORDER_BITS,
|
2009-04-02 23:56:45 +00:00
|
|
|
};
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2024-08-22 13:50:09 +00:00
|
|
|
#define AS_FOLIO_ORDER_BITS_MASK ((1u << AS_FOLIO_ORDER_BITS) - 1)
|
|
|
|
#define AS_FOLIO_ORDER_MIN_MASK (AS_FOLIO_ORDER_BITS_MASK << AS_FOLIO_ORDER_MIN)
|
|
|
|
#define AS_FOLIO_ORDER_MAX_MASK (AS_FOLIO_ORDER_BITS_MASK << AS_FOLIO_ORDER_MAX)
|
|
|
|
#define AS_FOLIO_ORDER_MASK (AS_FOLIO_ORDER_MIN_MASK | AS_FOLIO_ORDER_MAX_MASK)
|
|
|
|
|
2017-07-06 11:02:26 +00:00
|
|
|
/**
|
|
|
|
* mapping_set_error - record a writeback error in the address_space
|
2020-04-02 04:07:55 +00:00
|
|
|
* @mapping: the mapping in which an error should be set
|
|
|
|
* @error: the error to set in the mapping
|
2017-07-06 11:02:26 +00:00
|
|
|
*
|
|
|
|
* When writeback fails in some way, we must record that error so that
|
|
|
|
* userspace can be informed when fsync and the like are called. We endeavor
|
|
|
|
* to report errors on any file that was open at the time of the error. Some
|
|
|
|
* internal callers also need to know when writeback errors have occurred.
|
|
|
|
*
|
|
|
|
* When a writeback error occurs, most filesystems will want to call
|
|
|
|
* mapping_set_error to record the error in the mapping so that it can be
|
|
|
|
* reported when the application calls fsync(2).
|
|
|
|
*/
|
2007-05-08 07:23:25 +00:00
|
|
|
static inline void mapping_set_error(struct address_space *mapping, int error)
|
|
|
|
{
|
2017-07-06 11:02:26 +00:00
|
|
|
if (likely(!error))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Record in wb_err for checkers using errseq_t based tracking */
|
vfs: track per-sb writeback errors and report them to syncfs
Patch series "vfs: have syncfs() return error when there are writeback
errors", v6.
Currently, syncfs does not return errors when one of the inodes fails to
be written back. It will return errors based on the legacy AS_EIO and
AS_ENOSPC flags when syncing out the block device fails, but that's not
particularly helpful for filesystems that aren't backed by a blockdev.
It's also possible for a stray sync to lose those errors.
The basic idea in this set is to track writeback errors at the
superblock level, so that we can quickly and easily check whether
something bad happened without having to fsync each file individually.
syncfs is then changed to reliably report writeback errors after they
occur, much in the same fashion as fsync does now.
This patch (of 2):
Usually we suggest that applications call fsync when they want to ensure
that all data written to the file has made it to the backing store, but
that can be inefficient when there are a lot of open files.
Calling syncfs on the filesystem can be more efficient in some
situations, but the error reporting doesn't currently work the way most
people expect. If a single inode on a filesystem reports a writeback
error, syncfs won't necessarily return an error. syncfs only returns an
error if __sync_blockdev fails, and on some filesystems that's a no-op.
It would be better if syncfs reported an error if there were any
writeback failures. Then applications could call syncfs to see if there
are any errors on any open files, and could then call fsync on all of
the other descriptors to figure out which one failed.
This patch adds a new errseq_t to struct super_block, and has
mapping_set_error also record writeback errors there.
To report those errors, we also need to keep an errseq_t in struct file
to act as a cursor. This patch adds a dedicated field for that purpose,
which slots nicely into 4 bytes of padding at the end of struct file on
x86_64.
An earlier version of this patch used an O_PATH file descriptor to cue
the kernel that the open file should track the superblock error and not
the inode's writeback error.
I think that API is just too weird though. This is simpler and should
make syncfs error reporting "just work" even if someone is multiplexing
fsync and syncfs on the same fds.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Andres Freund <andres@anarazel.de>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: David Howells <dhowells@redhat.com>
Link: http://lkml.kernel.org/r/20200428135155.19223-1-jlayton@kernel.org
Link: http://lkml.kernel.org/r/20200428135155.19223-2-jlayton@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-02 04:45:36 +00:00
|
|
|
__filemap_set_wb_err(mapping, error);
|
|
|
|
|
|
|
|
/* Record it in superblock */
|
2020-10-11 06:16:37 +00:00
|
|
|
if (mapping->host)
|
|
|
|
errseq_set(&mapping->host->i_sb->s_wb_err, error);
|
2017-07-06 11:02:26 +00:00
|
|
|
|
|
|
|
/* Record it in flags for now, for legacy callers */
|
|
|
|
if (error == -ENOSPC)
|
|
|
|
set_bit(AS_ENOSPC, &mapping->flags);
|
|
|
|
else
|
|
|
|
set_bit(AS_EIO, &mapping->flags);
|
2007-05-08 07:23:25 +00:00
|
|
|
}
|
|
|
|
|
2008-10-19 03:26:42 +00:00
|
|
|
static inline void mapping_set_unevictable(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_UNEVICTABLE, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
2008-10-19 03:26:43 +00:00
|
|
|
static inline void mapping_clear_unevictable(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
clear_bit(AS_UNEVICTABLE, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
mm: swap: make page_evictable() inline
When backporting commit 9c4e6b1a7027 ("mm, mlock, vmscan: no more skipping
pagevecs") to our 4.9 kernel, our test bench noticed around 10% down with
a couple of vm-scalability's test cases (lru-file-readonce,
lru-file-readtwice and lru-file-mmap-read). I didn't see that much down
on my VM (32c-64g-2nodes). It might be caused by the test configuration,
which is 32c-256g with NUMA disabled and the tests were run in root memcg,
so the tests actually stress only one inactive and active lru. It sounds
not very usual in mordern production environment.
That commit did two major changes:
1. Call page_evictable()
2. Use smp_mb to force the PG_lru set visible
It looks they contribute the most overhead. The page_evictable() is a
function which does function prologue and epilogue, and that was used by
page reclaim path only. However, lru add is a very hot path, so it sounds
better to make it inline. However, it calls page_mapping() which is not
inlined either, but the disassemble shows it doesn't do push and pop
operations and it sounds not very straightforward to inline it.
Other than this, it sounds smp_mb() is not necessary for x86 since
SetPageLRU is atomic which enforces memory barrier already, replace it
with smp_mb__after_atomic() in the following patch.
With the two fixes applied, the tests can get back around 5% on that test
bench and get back normal on my VM. Since the test bench configuration is
not that usual and I also saw around 6% up on the latest upstream, so it
sounds good enough IMHO.
The below is test data (lru-file-readtwice throughput) against the v5.6-rc4:
mainline w/ inline fix
150MB 154MB
With this patch the throughput gets 2.67% up. The data with using
smp_mb__after_atomic() is showed in the following patch.
Shakeel Butt did the below test:
On a real machine with limiting the 'dd' on a single node and reading 100
GiB sparse file (less than a single node). Just ran a single instance to
not cause the lru lock contention. The cmdline used is "dd if=file-100GiB
of=/dev/null bs=4k". Ran the cmd 10 times with drop_caches in between and
measured the time it took.
Without patch: 56.64143 +- 0.672 sec
With patches: 56.10 +- 0.21 sec
[akpm@linux-foundation.org: move page_evictable() to internal.h]
Fixes: 9c4e6b1a7027 ("mm, mlock, vmscan: no more skipping pagevecs")
Signed-off-by: Yang Shi <yang.shi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Tested-by: Shakeel Butt <shakeelb@google.com>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Link: http://lkml.kernel.org/r/1584500541-46817-1-git-send-email-yang.shi@linux.alibaba.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-04-02 04:06:20 +00:00
|
|
|
static inline bool mapping_unevictable(struct address_space *mapping)
|
2008-10-19 03:26:42 +00:00
|
|
|
{
|
mm: swap: make page_evictable() inline
When backporting commit 9c4e6b1a7027 ("mm, mlock, vmscan: no more skipping
pagevecs") to our 4.9 kernel, our test bench noticed around 10% down with
a couple of vm-scalability's test cases (lru-file-readonce,
lru-file-readtwice and lru-file-mmap-read). I didn't see that much down
on my VM (32c-64g-2nodes). It might be caused by the test configuration,
which is 32c-256g with NUMA disabled and the tests were run in root memcg,
so the tests actually stress only one inactive and active lru. It sounds
not very usual in mordern production environment.
That commit did two major changes:
1. Call page_evictable()
2. Use smp_mb to force the PG_lru set visible
It looks they contribute the most overhead. The page_evictable() is a
function which does function prologue and epilogue, and that was used by
page reclaim path only. However, lru add is a very hot path, so it sounds
better to make it inline. However, it calls page_mapping() which is not
inlined either, but the disassemble shows it doesn't do push and pop
operations and it sounds not very straightforward to inline it.
Other than this, it sounds smp_mb() is not necessary for x86 since
SetPageLRU is atomic which enforces memory barrier already, replace it
with smp_mb__after_atomic() in the following patch.
With the two fixes applied, the tests can get back around 5% on that test
bench and get back normal on my VM. Since the test bench configuration is
not that usual and I also saw around 6% up on the latest upstream, so it
sounds good enough IMHO.
The below is test data (lru-file-readtwice throughput) against the v5.6-rc4:
mainline w/ inline fix
150MB 154MB
With this patch the throughput gets 2.67% up. The data with using
smp_mb__after_atomic() is showed in the following patch.
Shakeel Butt did the below test:
On a real machine with limiting the 'dd' on a single node and reading 100
GiB sparse file (less than a single node). Just ran a single instance to
not cause the lru lock contention. The cmdline used is "dd if=file-100GiB
of=/dev/null bs=4k". Ran the cmd 10 times with drop_caches in between and
measured the time it took.
Without patch: 56.64143 +- 0.672 sec
With patches: 56.10 +- 0.21 sec
[akpm@linux-foundation.org: move page_evictable() to internal.h]
Fixes: 9c4e6b1a7027 ("mm, mlock, vmscan: no more skipping pagevecs")
Signed-off-by: Yang Shi <yang.shi@linux.alibaba.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Tested-by: Shakeel Butt <shakeelb@google.com>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Link: http://lkml.kernel.org/r/1584500541-46817-1-git-send-email-yang.shi@linux.alibaba.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-04-02 04:06:20 +00:00
|
|
|
return mapping && test_bit(AS_UNEVICTABLE, &mapping->flags);
|
2008-10-19 03:26:42 +00:00
|
|
|
}
|
|
|
|
|
2014-04-03 21:47:49 +00:00
|
|
|
static inline void mapping_set_exiting(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_EXITING, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mapping_exiting(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return test_bit(AS_EXITING, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
mm: don't use radix tree writeback tags for pages in swap cache
File pages use a set of radix tree tags (DIRTY, TOWRITE, WRITEBACK,
etc.) to accelerate finding the pages with a specific tag in the radix
tree during inode writeback. But for anonymous pages in the swap cache,
there is no inode writeback. So there is no need to find the pages with
some writeback tags in the radix tree. It is not necessary to touch
radix tree writeback tags for pages in the swap cache.
Per Rik van Riel's suggestion, a new flag AS_NO_WRITEBACK_TAGS is
introduced for address spaces which don't need to update the writeback
tags. The flag is set for swap caches. It may be used for DAX file
systems, etc.
With this patch, the swap out bandwidth improved 22.3% (from ~1.2GB/s to
~1.48GBps) in the vm-scalability swap-w-seq test case with 8 processes.
The test is done on a Xeon E5 v3 system. The swap device used is a RAM
simulated PMEM (persistent memory) device. The improvement comes from
the reduced contention on the swap cache radix tree lock. To test
sequential swapping out, the test case uses 8 processes, which
sequentially allocate and write to the anonymous pages until RAM and
part of the swap device is used up.
Details of comparison is as follow,
base base+patch
---------------- --------------------------
%stddev %change %stddev
\ | \
2506952 ± 2% +28.1% 3212076 ± 7% vm-scalability.throughput
1207402 ± 7% +22.3% 1476578 ± 6% vmstat.swap.so
10.86 ± 12% -23.4% 8.31 ± 16% perf-profile.cycles-pp._raw_spin_lock_irq.__add_to_swap_cache.add_to_swap_cache.add_to_swap.shrink_page_list
10.82 ± 13% -33.1% 7.24 ± 14% perf-profile.cycles-pp._raw_spin_lock_irqsave.__remove_mapping.shrink_page_list.shrink_inactive_list.shrink_zone_memcg
10.36 ± 11% -100.0% 0.00 ± -1% perf-profile.cycles-pp._raw_spin_lock_irqsave.__test_set_page_writeback.bdev_write_page.__swap_writepage.swap_writepage
10.52 ± 12% -100.0% 0.00 ± -1% perf-profile.cycles-pp._raw_spin_lock_irqsave.test_clear_page_writeback.end_page_writeback.page_endio.pmem_rw_page
Link: http://lkml.kernel.org/r/1472578089-5560-1-git-send-email-ying.huang@intel.com
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Shaohua Li <shli@kernel.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Tejun Heo <tj@kernel.org>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-07 23:59:30 +00:00
|
|
|
static inline void mapping_set_no_writeback_tags(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mapping_use_writeback_tags(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return !test_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
mm, netfs, fscache: stop read optimisation when folio removed from pagecache
Fscache has an optimisation by which reads from the cache are skipped
until we know that (a) there's data there to be read and (b) that data
isn't entirely covered by pages resident in the netfs pagecache. This is
done with two flags manipulated by fscache_note_page_release():
if (...
test_bit(FSCACHE_COOKIE_HAVE_DATA, &cookie->flags) &&
test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags))
clear_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
where the NO_DATA_TO_READ flag causes cachefiles_prepare_read() to
indicate that netfslib should download from the server or clear the page
instead.
The fscache_note_page_release() function is intended to be called from
->releasepage() - but that only gets called if PG_private or PG_private_2
is set - and currently the former is at the discretion of the network
filesystem and the latter is only set whilst a page is being written to
the cache, so sometimes we miss clearing the optimisation.
Fix this by following Willy's suggestion[1] and adding an address_space
flag, AS_RELEASE_ALWAYS, that causes filemap_release_folio() to always call
->release_folio() if it's set, even if PG_private or PG_private_2 aren't
set.
Note that this would require folio_test_private() and page_has_private() to
become more complicated. To avoid that, in the places[*] where these are
used to conditionalise calls to filemap_release_folio() and
try_to_release_page(), the tests are removed the those functions just
jumped to unconditionally and the test is performed there.
[*] There are some exceptions in vmscan.c where the check guards more than
just a call to the releaser. I've added a function, folio_needs_release()
to wrap all the checks for that.
AS_RELEASE_ALWAYS should be set if a non-NULL cookie is obtained from
fscache and cleared in ->evict_inode() before truncate_inode_pages_final()
is called.
Additionally, the FSCACHE_COOKIE_NO_DATA_TO_READ flag needs to be cleared
and the optimisation cancelled if a cachefiles object already contains data
when we open it.
[dwysocha@redhat.com: call folio_mapping() inside folio_needs_release()]
Link: https://github.com/DaveWysochanskiRH/kernel/commit/902c990e311120179fa5de99d68364b2947b79ec
Link: https://lkml.kernel.org/r/20230628104852.3391651-3-dhowells@redhat.com
Fixes: 1f67e6d0b188 ("fscache: Provide a function to note the release of a page")
Fixes: 047487c947e8 ("cachefiles: Implement the I/O routines")
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
Reported-by: Rohith Surabattula <rohiths.msft@gmail.com>
Suggested-by: Matthew Wilcox <willy@infradead.org>
Tested-by: SeongJae Park <sj@kernel.org>
Cc: Daire Byrne <daire.byrne@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Steve French <sfrench@samba.org>
Cc: Shyam Prasad N <nspmangalore@gmail.com>
Cc: Rohith Surabattula <rohiths.msft@gmail.com>
Cc: Dave Wysochanski <dwysocha@redhat.com>
Cc: Dominique Martinet <asmadeus@codewreck.org>
Cc: Ilya Dryomov <idryomov@gmail.com>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Cc: Jingbo Xu <jefflexu@linux.alibaba.com>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-06-28 10:48:52 +00:00
|
|
|
static inline bool mapping_release_always(const struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return test_bit(AS_RELEASE_ALWAYS, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mapping_set_release_always(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_RELEASE_ALWAYS, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mapping_clear_release_always(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
clear_bit(AS_RELEASE_ALWAYS, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
2023-10-25 14:10:17 +00:00
|
|
|
static inline bool mapping_stable_writes(const struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return test_bit(AS_STABLE_WRITES, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mapping_set_stable_writes(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_STABLE_WRITES, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mapping_clear_stable_writes(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
clear_bit(AS_STABLE_WRITES, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
2024-07-11 17:56:54 +00:00
|
|
|
static inline void mapping_set_inaccessible(struct address_space *mapping)
|
2023-10-27 18:21:56 +00:00
|
|
|
{
|
|
|
|
/*
|
2024-07-11 17:56:54 +00:00
|
|
|
* It's expected inaccessible mappings are also unevictable. Compaction
|
2023-10-27 18:21:56 +00:00
|
|
|
* migrate scanner (isolate_migratepages_block()) relies on this to
|
|
|
|
* reduce page locking.
|
|
|
|
*/
|
|
|
|
set_bit(AS_UNEVICTABLE, &mapping->flags);
|
2024-07-11 17:56:54 +00:00
|
|
|
set_bit(AS_INACCESSIBLE, &mapping->flags);
|
2023-10-27 18:21:56 +00:00
|
|
|
}
|
|
|
|
|
2024-07-11 17:56:54 +00:00
|
|
|
static inline bool mapping_inaccessible(struct address_space *mapping)
|
2023-10-27 18:21:56 +00:00
|
|
|
{
|
2024-07-11 17:56:54 +00:00
|
|
|
return test_bit(AS_INACCESSIBLE, &mapping->flags);
|
2023-10-27 18:21:56 +00:00
|
|
|
}
|
|
|
|
|
mm: add AS_WRITEBACK_INDETERMINATE mapping flag
Patch series "fuse: remove temp page copies in writeback", v6.
The purpose of this patchset is to help make writeback-cache write
performance in FUSE filesystems as fast as possible.
In the current FUSE writeback design (see commit 3be5a52b30aa ("fuse:
support writable mmap"))), a temp page is allocated for every dirty page
to be written back, the contents of the dirty page are copied over to the
temp page, and the temp page gets handed to the server to write back.
This is done so that writeback may be immediately cleared on the dirty
page, and this in turn is done for two reasons:
a) in order to mitigate the following deadlock scenario that may arise
if reclaim waits on writeback on the dirty page to complete (more
details can be found in this thread [1]):
* single-threaded FUSE server is in the middle of handling a request
that needs a memory allocation
* memory allocation triggers direct reclaim
* direct reclaim waits on a folio under writeback
* the FUSE server can't write back the folio since it's stuck in
direct reclaim
b) in order to unblock internal (eg sync, page compaction) waits on
writeback without needing the server to complete writing back to disk,
which may take an indeterminate amount of time.
Allocating and copying dirty pages to temp pages is the biggest
performance bottleneck for FUSE writeback. This patchset aims to get rid
of the temp page altogether (which will also allow us to get rid of the
internal FUSE rb tree that is needed to keep track of writeback status on
the temp pages). Benchmarks show approximately a 20% improvement in
throughput for 4k block-size writes and a 45% improvement for 1M
block-size writes.
With removing the temp page, writeback state is now only cleared on the
dirty page after the server has written it back to disk. This may take an
indeterminate amount of time. As well, there is also the possibility of
malicious or well-intentioned but buggy servers where writeback may in the
worst case scenario, never complete. This means that any
folio_wait_writeback() on a dirty page belonging to a FUSE filesystem
needs to be carefully audited.
In particular, these are the cases that need to be accounted for:
* potentially deadlocking in reclaim, as mentioned above
* potentially stalling sync(2)
* potentially stalling page migration / compaction
This patchset adds a new mapping flag, AS_WRITEBACK_INDETERMINATE, which
filesystems may set on its inode mappings to indicate that writeback
operations may take an indeterminate amount of time to complete. FUSE
will set this flag on its mappings. This patchset adds checks to the
critical parts of reclaim, sync, and page migration logic where writeback
may be waited on.
Please note the following:
* For sync(2), waiting on writeback will be skipped for FUSE, but this has no
effect on existing behavior. Dirty FUSE pages are already not guaranteed to
be written to disk by the time sync(2) returns (eg writeback is cleared on
the dirty page but the server may not have written out the temp page to disk
yet). If the caller wishes to ensure the data has actually been synced to
disk, they should use fsync(2)/fdatasync(2) instead.
* AS_WRITEBACK_INDETERMINATE does not indicate that the folios should never be
waited on when in writeback. There are some cases where the wait is
desirable. For example, for the sync_file_range() syscall, it is fine to
wait on the writeback since the caller passes in a fd for the operation.
[1] https://lore.kernel.org/linux-kernel/495d2400-1d96-4924-99d3-8b2952e05fc3@linux.alibaba.com/
This patch (of 5):
Add a new mapping flag AS_WRITEBACK_INDETERMINATE which filesystems may
set to indicate that writing back to disk may take an indeterminate amount
of time to complete. Extra caution should be taken when waiting on
writeback for folios belonging to mappings where this flag is set.
Link: https://lkml.kernel.org/r/20241122232359.429647-1-joannelkoong@gmail.com
Link: https://lkml.kernel.org/r/20241122232359.429647-2-joannelkoong@gmail.com
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: Bernd Schubert <bernd.schubert@fastmail.fm>
Cc: Jingbo Xu <jefflexu@linux.alibaba.com>
Cc: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-22 23:23:55 +00:00
|
|
|
static inline void mapping_set_writeback_indeterminate(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
set_bit(AS_WRITEBACK_INDETERMINATE, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool mapping_writeback_indeterminate(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return test_bit(AS_WRITEBACK_INDETERMINATE, &mapping->flags);
|
|
|
|
}
|
|
|
|
|
2005-10-07 06:46:04 +00:00
|
|
|
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2016-10-11 20:56:04 +00:00
|
|
|
return mapping->gfp_mask;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-11-07 00:28:49 +00:00
|
|
|
/* Restricts the given gfp_mask to what the mapping allows. */
|
|
|
|
static inline gfp_t mapping_gfp_constraint(struct address_space *mapping,
|
|
|
|
gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
return mapping_gfp_mask(mapping) & gfp_mask;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* This is non-atomic. Only to be used before the mapping is activated.
|
|
|
|
* Probably needs a barrier...
|
|
|
|
*/
|
2005-10-21 07:22:44 +00:00
|
|
|
static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2016-10-11 20:56:04 +00:00
|
|
|
m->gfp_mask = mask;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 11:49:38 +00:00
|
|
|
/*
|
|
|
|
* There are some parts of the kernel which assume that PMD entries
|
|
|
|
* are exactly HPAGE_PMD_ORDER. Those should be fixed, but until then,
|
|
|
|
* limit the maximum allocation order to PMD size. I'm not aware of any
|
|
|
|
* assumptions about maximum order if THP are disabled, but 8 seems like
|
|
|
|
* a good order (that's 1MB if you're using 4kB pages)
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
mm/filemap: make MAX_PAGECACHE_ORDER acceptable to xarray
Patch series "mm/filemap: Limit page cache size to that supported by
xarray", v2.
Currently, xarray can't support arbitrary page cache size. More details
can be found from the WARN_ON() statement in xas_split_alloc(). In our
test whose code is attached below, we hit the WARN_ON() on ARM64 system
where the base page size is 64KB and huge page size is 512MB. The issue
was reported long time ago and some discussions on it can be found here
[1].
[1] https://www.spinics.net/lists/linux-xfs/msg75404.html
In order to fix the issue, we need to adjust MAX_PAGECACHE_ORDER to one
supported by xarray and avoid PMD-sized page cache if needed. The code
changes are suggested by David Hildenbrand.
PATCH[1] adjusts MAX_PAGECACHE_ORDER to that supported by xarray
PATCH[2-3] avoids PMD-sized page cache in the synchronous readahead path
PATCH[4] avoids PMD-sized page cache for shmem files if needed
Test program
============
# cat test.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#define TEST_XFS_FILENAME "/tmp/data"
#define TEST_SHMEM_FILENAME "/dev/shm/data"
#define TEST_MEM_SIZE 0x20000000
int main(int argc, char **argv)
{
const char *filename;
int fd = 0;
void *buf = (void *)-1, *p;
int pgsize = getpagesize();
int ret;
if (pgsize != 0x10000) {
fprintf(stderr, "64KB base page size is required\n");
return -EPERM;
}
system("echo force > /sys/kernel/mm/transparent_hugepage/shmem_enabled");
system("rm -fr /tmp/data");
system("rm -fr /dev/shm/data");
system("echo 1 > /proc/sys/vm/drop_caches");
/* Open xfs or shmem file */
filename = TEST_XFS_FILENAME;
if (argc > 1 && !strcmp(argv[1], "shmem"))
filename = TEST_SHMEM_FILENAME;
fd = open(filename, O_CREAT | O_RDWR | O_TRUNC);
if (fd < 0) {
fprintf(stderr, "Unable to open <%s>\n", filename);
return -EIO;
}
/* Extend file size */
ret = ftruncate(fd, TEST_MEM_SIZE);
if (ret) {
fprintf(stderr, "Error %d to ftruncate()\n", ret);
goto cleanup;
}
/* Create VMA */
buf = mmap(NULL, TEST_MEM_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == (void *)-1) {
fprintf(stderr, "Unable to mmap <%s>\n", filename);
goto cleanup;
}
fprintf(stdout, "mapped buffer at 0x%p\n", buf);
ret = madvise(buf, TEST_MEM_SIZE, MADV_HUGEPAGE);
if (ret) {
fprintf(stderr, "Unable to madvise(MADV_HUGEPAGE)\n");
goto cleanup;
}
/* Populate VMA */
ret = madvise(buf, TEST_MEM_SIZE, MADV_POPULATE_WRITE);
if (ret) {
fprintf(stderr, "Error %d to madvise(MADV_POPULATE_WRITE)\n", ret);
goto cleanup;
}
/* Punch the file to enforce xarray split */
ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
TEST_MEM_SIZE - pgsize, pgsize);
if (ret)
fprintf(stderr, "Error %d to fallocate()\n", ret);
cleanup:
if (buf != (void *)-1)
munmap(buf, TEST_MEM_SIZE);
if (fd > 0)
close(fd);
return 0;
}
# gcc test.c -o test
# cat /proc/1/smaps | grep KernelPageSize | head -n 1
KernelPageSize: 64 kB
# ./test shmem
:
------------[ cut here ]------------
WARNING: CPU: 17 PID: 5253 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set nf_tables rfkill nfnetlink vfat fat virtio_balloon \
drm fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
virtio_net sha1_ce net_failover failover virtio_console virtio_blk \
dimlib virtio_mmio
CPU: 17 PID: 5253 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #12
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff80008a92f5b0
x29: ffff80008a92f5b0 x28: ffff80008a92f610 x27: ffff80008a92f728
x26: 0000000000000cc0 x25: 000000000000000d x24: ffff0000cf00c858
x23: ffff80008a92f610 x22: ffffffdfc0600000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0600000 x18: 0000000000000000
x17: 0000000000000000 x16: 0000018000000000 x15: 3374004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 3374000000000000 x10: 3374e1c0ffff6000 x9 : ffffb463a84c681c
x8 : 0000000000000003 x7 : 0000000000000000 x6 : ffff00011c976ce0
x5 : ffffb463aa47e378 x4 : 0000000000000000 x3 : 0000000000000cc0
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
shmem_undo_range+0x2bc/0x6a8
shmem_fallocate+0x134/0x430
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
This patch (of 4):
The largest page cache order can be HPAGE_PMD_ORDER (13) on ARM64 with
64KB base page size. The xarray entry with this order can't be split as
the following error messages indicate.
------------[ cut here ]------------
WARNING: CPU: 35 PID: 7484 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set rfkill nf_tables nfnetlink vfat fat virtio_balloon drm \
fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
sha1_ce virtio_net net_failover virtio_console virtio_blk failover \
dimlib virtio_mmio
CPU: 35 PID: 7484 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #9
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff800087a4f6c0
x29: ffff800087a4f6c0 x28: ffff800087a4f720 x27: 000000001fffffff
x26: 0000000000000c40 x25: 000000000000000d x24: ffff00010625b858
x23: ffff800087a4f720 x22: ffffffdfc0780000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0780000 x18: 000000001ff40000
x17: 00000000ffffffff x16: 0000018000000000 x15: 51ec004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 51ec000000000000 x10: 51ece1c0ffff8000 x9 : ffffbeb961a44d28
x8 : 0000000000000003 x7 : ffffffdfc0456420 x6 : ffff0000e1aa6eb8
x5 : 20bf08b4fe778fca x4 : ffffffdfc0456420 x3 : 0000000000000c40
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
truncate_inode_pages_range+0x1b4/0x4a8
truncate_pagecache_range+0x84/0xa0
xfs_flush_unmap_range+0x70/0x90 [xfs]
xfs_file_fallocate+0xfc/0x4d8 [xfs]
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
Fix it by decreasing MAX_PAGECACHE_ORDER to the largest supported order
by xarray. For this specific case, MAX_PAGECACHE_ORDER is dropped from
13 to 11 when CONFIG_BASE_SMALL is disabled.
Link: https://lkml.kernel.org/r/20240627003953.1262512-1-gshan@redhat.com
Link: https://lkml.kernel.org/r/20240627003953.1262512-2-gshan@redhat.com
Fixes: 793917d997df ("mm/readahead: Add large folio readahead")
Signed-off-by: Gavin Shan <gshan@redhat.com>
Suggested-by: David Hildenbrand <david@redhat.com>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Darrick J. Wong <djwong@kernel.org>
Cc: Don Dutile <ddutile@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: William Kucharski <william.kucharski@oracle.com>
Cc: Zhenyu Zhang <zhenyzha@redhat.com>
Cc: <stable@vger.kernel.org> [5.18+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-06-27 00:39:49 +00:00
|
|
|
#define PREFERRED_MAX_PAGECACHE_ORDER HPAGE_PMD_ORDER
|
2024-05-21 11:49:38 +00:00
|
|
|
#else
|
mm/filemap: make MAX_PAGECACHE_ORDER acceptable to xarray
Patch series "mm/filemap: Limit page cache size to that supported by
xarray", v2.
Currently, xarray can't support arbitrary page cache size. More details
can be found from the WARN_ON() statement in xas_split_alloc(). In our
test whose code is attached below, we hit the WARN_ON() on ARM64 system
where the base page size is 64KB and huge page size is 512MB. The issue
was reported long time ago and some discussions on it can be found here
[1].
[1] https://www.spinics.net/lists/linux-xfs/msg75404.html
In order to fix the issue, we need to adjust MAX_PAGECACHE_ORDER to one
supported by xarray and avoid PMD-sized page cache if needed. The code
changes are suggested by David Hildenbrand.
PATCH[1] adjusts MAX_PAGECACHE_ORDER to that supported by xarray
PATCH[2-3] avoids PMD-sized page cache in the synchronous readahead path
PATCH[4] avoids PMD-sized page cache for shmem files if needed
Test program
============
# cat test.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#define TEST_XFS_FILENAME "/tmp/data"
#define TEST_SHMEM_FILENAME "/dev/shm/data"
#define TEST_MEM_SIZE 0x20000000
int main(int argc, char **argv)
{
const char *filename;
int fd = 0;
void *buf = (void *)-1, *p;
int pgsize = getpagesize();
int ret;
if (pgsize != 0x10000) {
fprintf(stderr, "64KB base page size is required\n");
return -EPERM;
}
system("echo force > /sys/kernel/mm/transparent_hugepage/shmem_enabled");
system("rm -fr /tmp/data");
system("rm -fr /dev/shm/data");
system("echo 1 > /proc/sys/vm/drop_caches");
/* Open xfs or shmem file */
filename = TEST_XFS_FILENAME;
if (argc > 1 && !strcmp(argv[1], "shmem"))
filename = TEST_SHMEM_FILENAME;
fd = open(filename, O_CREAT | O_RDWR | O_TRUNC);
if (fd < 0) {
fprintf(stderr, "Unable to open <%s>\n", filename);
return -EIO;
}
/* Extend file size */
ret = ftruncate(fd, TEST_MEM_SIZE);
if (ret) {
fprintf(stderr, "Error %d to ftruncate()\n", ret);
goto cleanup;
}
/* Create VMA */
buf = mmap(NULL, TEST_MEM_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == (void *)-1) {
fprintf(stderr, "Unable to mmap <%s>\n", filename);
goto cleanup;
}
fprintf(stdout, "mapped buffer at 0x%p\n", buf);
ret = madvise(buf, TEST_MEM_SIZE, MADV_HUGEPAGE);
if (ret) {
fprintf(stderr, "Unable to madvise(MADV_HUGEPAGE)\n");
goto cleanup;
}
/* Populate VMA */
ret = madvise(buf, TEST_MEM_SIZE, MADV_POPULATE_WRITE);
if (ret) {
fprintf(stderr, "Error %d to madvise(MADV_POPULATE_WRITE)\n", ret);
goto cleanup;
}
/* Punch the file to enforce xarray split */
ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
TEST_MEM_SIZE - pgsize, pgsize);
if (ret)
fprintf(stderr, "Error %d to fallocate()\n", ret);
cleanup:
if (buf != (void *)-1)
munmap(buf, TEST_MEM_SIZE);
if (fd > 0)
close(fd);
return 0;
}
# gcc test.c -o test
# cat /proc/1/smaps | grep KernelPageSize | head -n 1
KernelPageSize: 64 kB
# ./test shmem
:
------------[ cut here ]------------
WARNING: CPU: 17 PID: 5253 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set nf_tables rfkill nfnetlink vfat fat virtio_balloon \
drm fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
virtio_net sha1_ce net_failover failover virtio_console virtio_blk \
dimlib virtio_mmio
CPU: 17 PID: 5253 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #12
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff80008a92f5b0
x29: ffff80008a92f5b0 x28: ffff80008a92f610 x27: ffff80008a92f728
x26: 0000000000000cc0 x25: 000000000000000d x24: ffff0000cf00c858
x23: ffff80008a92f610 x22: ffffffdfc0600000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0600000 x18: 0000000000000000
x17: 0000000000000000 x16: 0000018000000000 x15: 3374004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 3374000000000000 x10: 3374e1c0ffff6000 x9 : ffffb463a84c681c
x8 : 0000000000000003 x7 : 0000000000000000 x6 : ffff00011c976ce0
x5 : ffffb463aa47e378 x4 : 0000000000000000 x3 : 0000000000000cc0
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
shmem_undo_range+0x2bc/0x6a8
shmem_fallocate+0x134/0x430
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
This patch (of 4):
The largest page cache order can be HPAGE_PMD_ORDER (13) on ARM64 with
64KB base page size. The xarray entry with this order can't be split as
the following error messages indicate.
------------[ cut here ]------------
WARNING: CPU: 35 PID: 7484 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set rfkill nf_tables nfnetlink vfat fat virtio_balloon drm \
fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
sha1_ce virtio_net net_failover virtio_console virtio_blk failover \
dimlib virtio_mmio
CPU: 35 PID: 7484 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #9
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff800087a4f6c0
x29: ffff800087a4f6c0 x28: ffff800087a4f720 x27: 000000001fffffff
x26: 0000000000000c40 x25: 000000000000000d x24: ffff00010625b858
x23: ffff800087a4f720 x22: ffffffdfc0780000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0780000 x18: 000000001ff40000
x17: 00000000ffffffff x16: 0000018000000000 x15: 51ec004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 51ec000000000000 x10: 51ece1c0ffff8000 x9 : ffffbeb961a44d28
x8 : 0000000000000003 x7 : ffffffdfc0456420 x6 : ffff0000e1aa6eb8
x5 : 20bf08b4fe778fca x4 : ffffffdfc0456420 x3 : 0000000000000c40
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
truncate_inode_pages_range+0x1b4/0x4a8
truncate_pagecache_range+0x84/0xa0
xfs_flush_unmap_range+0x70/0x90 [xfs]
xfs_file_fallocate+0xfc/0x4d8 [xfs]
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
Fix it by decreasing MAX_PAGECACHE_ORDER to the largest supported order
by xarray. For this specific case, MAX_PAGECACHE_ORDER is dropped from
13 to 11 when CONFIG_BASE_SMALL is disabled.
Link: https://lkml.kernel.org/r/20240627003953.1262512-1-gshan@redhat.com
Link: https://lkml.kernel.org/r/20240627003953.1262512-2-gshan@redhat.com
Fixes: 793917d997df ("mm/readahead: Add large folio readahead")
Signed-off-by: Gavin Shan <gshan@redhat.com>
Suggested-by: David Hildenbrand <david@redhat.com>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Darrick J. Wong <djwong@kernel.org>
Cc: Don Dutile <ddutile@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: William Kucharski <william.kucharski@oracle.com>
Cc: Zhenyu Zhang <zhenyzha@redhat.com>
Cc: <stable@vger.kernel.org> [5.18+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-06-27 00:39:49 +00:00
|
|
|
#define PREFERRED_MAX_PAGECACHE_ORDER 8
|
2024-05-21 11:49:38 +00:00
|
|
|
#endif
|
|
|
|
|
mm/filemap: make MAX_PAGECACHE_ORDER acceptable to xarray
Patch series "mm/filemap: Limit page cache size to that supported by
xarray", v2.
Currently, xarray can't support arbitrary page cache size. More details
can be found from the WARN_ON() statement in xas_split_alloc(). In our
test whose code is attached below, we hit the WARN_ON() on ARM64 system
where the base page size is 64KB and huge page size is 512MB. The issue
was reported long time ago and some discussions on it can be found here
[1].
[1] https://www.spinics.net/lists/linux-xfs/msg75404.html
In order to fix the issue, we need to adjust MAX_PAGECACHE_ORDER to one
supported by xarray and avoid PMD-sized page cache if needed. The code
changes are suggested by David Hildenbrand.
PATCH[1] adjusts MAX_PAGECACHE_ORDER to that supported by xarray
PATCH[2-3] avoids PMD-sized page cache in the synchronous readahead path
PATCH[4] avoids PMD-sized page cache for shmem files if needed
Test program
============
# cat test.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#define TEST_XFS_FILENAME "/tmp/data"
#define TEST_SHMEM_FILENAME "/dev/shm/data"
#define TEST_MEM_SIZE 0x20000000
int main(int argc, char **argv)
{
const char *filename;
int fd = 0;
void *buf = (void *)-1, *p;
int pgsize = getpagesize();
int ret;
if (pgsize != 0x10000) {
fprintf(stderr, "64KB base page size is required\n");
return -EPERM;
}
system("echo force > /sys/kernel/mm/transparent_hugepage/shmem_enabled");
system("rm -fr /tmp/data");
system("rm -fr /dev/shm/data");
system("echo 1 > /proc/sys/vm/drop_caches");
/* Open xfs or shmem file */
filename = TEST_XFS_FILENAME;
if (argc > 1 && !strcmp(argv[1], "shmem"))
filename = TEST_SHMEM_FILENAME;
fd = open(filename, O_CREAT | O_RDWR | O_TRUNC);
if (fd < 0) {
fprintf(stderr, "Unable to open <%s>\n", filename);
return -EIO;
}
/* Extend file size */
ret = ftruncate(fd, TEST_MEM_SIZE);
if (ret) {
fprintf(stderr, "Error %d to ftruncate()\n", ret);
goto cleanup;
}
/* Create VMA */
buf = mmap(NULL, TEST_MEM_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == (void *)-1) {
fprintf(stderr, "Unable to mmap <%s>\n", filename);
goto cleanup;
}
fprintf(stdout, "mapped buffer at 0x%p\n", buf);
ret = madvise(buf, TEST_MEM_SIZE, MADV_HUGEPAGE);
if (ret) {
fprintf(stderr, "Unable to madvise(MADV_HUGEPAGE)\n");
goto cleanup;
}
/* Populate VMA */
ret = madvise(buf, TEST_MEM_SIZE, MADV_POPULATE_WRITE);
if (ret) {
fprintf(stderr, "Error %d to madvise(MADV_POPULATE_WRITE)\n", ret);
goto cleanup;
}
/* Punch the file to enforce xarray split */
ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
TEST_MEM_SIZE - pgsize, pgsize);
if (ret)
fprintf(stderr, "Error %d to fallocate()\n", ret);
cleanup:
if (buf != (void *)-1)
munmap(buf, TEST_MEM_SIZE);
if (fd > 0)
close(fd);
return 0;
}
# gcc test.c -o test
# cat /proc/1/smaps | grep KernelPageSize | head -n 1
KernelPageSize: 64 kB
# ./test shmem
:
------------[ cut here ]------------
WARNING: CPU: 17 PID: 5253 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set nf_tables rfkill nfnetlink vfat fat virtio_balloon \
drm fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
virtio_net sha1_ce net_failover failover virtio_console virtio_blk \
dimlib virtio_mmio
CPU: 17 PID: 5253 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #12
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff80008a92f5b0
x29: ffff80008a92f5b0 x28: ffff80008a92f610 x27: ffff80008a92f728
x26: 0000000000000cc0 x25: 000000000000000d x24: ffff0000cf00c858
x23: ffff80008a92f610 x22: ffffffdfc0600000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0600000 x18: 0000000000000000
x17: 0000000000000000 x16: 0000018000000000 x15: 3374004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 3374000000000000 x10: 3374e1c0ffff6000 x9 : ffffb463a84c681c
x8 : 0000000000000003 x7 : 0000000000000000 x6 : ffff00011c976ce0
x5 : ffffb463aa47e378 x4 : 0000000000000000 x3 : 0000000000000cc0
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
shmem_undo_range+0x2bc/0x6a8
shmem_fallocate+0x134/0x430
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
This patch (of 4):
The largest page cache order can be HPAGE_PMD_ORDER (13) on ARM64 with
64KB base page size. The xarray entry with this order can't be split as
the following error messages indicate.
------------[ cut here ]------------
WARNING: CPU: 35 PID: 7484 at lib/xarray.c:1025 xas_split_alloc+0xf8/0x128
Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib \
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct \
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 \
ip_set rfkill nf_tables nfnetlink vfat fat virtio_balloon drm \
fuse xfs libcrc32c crct10dif_ce ghash_ce sha2_ce sha256_arm64 \
sha1_ce virtio_net net_failover virtio_console virtio_blk failover \
dimlib virtio_mmio
CPU: 35 PID: 7484 Comm: test Kdump: loaded Tainted: G W 6.10.0-rc5-gavin+ #9
Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20240524-1.el9 05/24/2024
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : xas_split_alloc+0xf8/0x128
lr : split_huge_page_to_list_to_order+0x1c4/0x720
sp : ffff800087a4f6c0
x29: ffff800087a4f6c0 x28: ffff800087a4f720 x27: 000000001fffffff
x26: 0000000000000c40 x25: 000000000000000d x24: ffff00010625b858
x23: ffff800087a4f720 x22: ffffffdfc0780000 x21: 0000000000000000
x20: 0000000000000000 x19: ffffffdfc0780000 x18: 000000001ff40000
x17: 00000000ffffffff x16: 0000018000000000 x15: 51ec004000000000
x14: 0000e00000000000 x13: 0000000000002000 x12: 0000000000000020
x11: 51ec000000000000 x10: 51ece1c0ffff8000 x9 : ffffbeb961a44d28
x8 : 0000000000000003 x7 : ffffffdfc0456420 x6 : ffff0000e1aa6eb8
x5 : 20bf08b4fe778fca x4 : ffffffdfc0456420 x3 : 0000000000000c40
x2 : 000000000000000d x1 : 000000000000000c x0 : 0000000000000000
Call trace:
xas_split_alloc+0xf8/0x128
split_huge_page_to_list_to_order+0x1c4/0x720
truncate_inode_partial_folio+0xdc/0x160
truncate_inode_pages_range+0x1b4/0x4a8
truncate_pagecache_range+0x84/0xa0
xfs_flush_unmap_range+0x70/0x90 [xfs]
xfs_file_fallocate+0xfc/0x4d8 [xfs]
vfs_fallocate+0x124/0x2e8
ksys_fallocate+0x4c/0xa0
__arm64_sys_fallocate+0x24/0x38
invoke_syscall.constprop.0+0x7c/0xd8
do_el0_svc+0xb4/0xd0
el0_svc+0x44/0x1d8
el0t_64_sync_handler+0x134/0x150
el0t_64_sync+0x17c/0x180
Fix it by decreasing MAX_PAGECACHE_ORDER to the largest supported order
by xarray. For this specific case, MAX_PAGECACHE_ORDER is dropped from
13 to 11 when CONFIG_BASE_SMALL is disabled.
Link: https://lkml.kernel.org/r/20240627003953.1262512-1-gshan@redhat.com
Link: https://lkml.kernel.org/r/20240627003953.1262512-2-gshan@redhat.com
Fixes: 793917d997df ("mm/readahead: Add large folio readahead")
Signed-off-by: Gavin Shan <gshan@redhat.com>
Suggested-by: David Hildenbrand <david@redhat.com>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Darrick J. Wong <djwong@kernel.org>
Cc: Don Dutile <ddutile@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: William Kucharski <william.kucharski@oracle.com>
Cc: Zhenyu Zhang <zhenyzha@redhat.com>
Cc: <stable@vger.kernel.org> [5.18+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-06-27 00:39:49 +00:00
|
|
|
/*
|
|
|
|
* xas_split_alloc() does not support arbitrary orders. This implies no
|
|
|
|
* 512MB THP on ARM64 with 64KB base page size.
|
|
|
|
*/
|
|
|
|
#define MAX_XAS_ORDER (XA_CHUNK_SHIFT * 2 - 1)
|
|
|
|
#define MAX_PAGECACHE_ORDER min(MAX_XAS_ORDER, PREFERRED_MAX_PAGECACHE_ORDER)
|
|
|
|
|
2024-08-22 13:50:18 +00:00
|
|
|
/*
|
|
|
|
* mapping_max_folio_size_supported() - Check the max folio size supported
|
|
|
|
*
|
|
|
|
* The filesystem should call this function at mount time if there is a
|
|
|
|
* requirement on the folio mapping size in the page cache.
|
|
|
|
*/
|
|
|
|
static inline size_t mapping_max_folio_size_supported(void)
|
|
|
|
{
|
|
|
|
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
|
|
|
|
return 1U << (PAGE_SHIFT + MAX_PAGECACHE_ORDER);
|
|
|
|
return PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2024-08-22 13:50:09 +00:00
|
|
|
/*
|
|
|
|
* mapping_set_folio_order_range() - Set the orders supported by a file.
|
|
|
|
* @mapping: The address space of the file.
|
|
|
|
* @min: Minimum folio order (between 0-MAX_PAGECACHE_ORDER inclusive).
|
|
|
|
* @max: Maximum folio order (between @min-MAX_PAGECACHE_ORDER inclusive).
|
|
|
|
*
|
|
|
|
* The filesystem should call this function in its inode constructor to
|
|
|
|
* indicate which base size (min) and maximum size (max) of folio the VFS
|
|
|
|
* can use to cache the contents of the file. This should only be used
|
|
|
|
* if the filesystem needs special handling of folio sizes (ie there is
|
|
|
|
* something the core cannot know).
|
|
|
|
* Do not tune it based on, eg, i_size.
|
|
|
|
*
|
|
|
|
* Context: This should not be called while the inode is active as it
|
|
|
|
* is non-atomic.
|
|
|
|
*/
|
|
|
|
static inline void mapping_set_folio_order_range(struct address_space *mapping,
|
|
|
|
unsigned int min,
|
|
|
|
unsigned int max)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (min > MAX_PAGECACHE_ORDER)
|
|
|
|
min = MAX_PAGECACHE_ORDER;
|
|
|
|
|
|
|
|
if (max > MAX_PAGECACHE_ORDER)
|
|
|
|
max = MAX_PAGECACHE_ORDER;
|
|
|
|
|
|
|
|
if (max < min)
|
|
|
|
max = min;
|
|
|
|
|
|
|
|
mapping->flags = (mapping->flags & ~AS_FOLIO_ORDER_MASK) |
|
|
|
|
(min << AS_FOLIO_ORDER_MIN) | (max << AS_FOLIO_ORDER_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mapping_set_folio_min_order(struct address_space *mapping,
|
|
|
|
unsigned int min)
|
|
|
|
{
|
|
|
|
mapping_set_folio_order_range(mapping, min, MAX_PAGECACHE_ORDER);
|
|
|
|
}
|
|
|
|
|
2021-08-29 10:07:03 +00:00
|
|
|
/**
|
|
|
|
* mapping_set_large_folios() - Indicate the file supports large folios.
|
2024-08-22 13:50:09 +00:00
|
|
|
* @mapping: The address space of the file.
|
2021-08-29 10:07:03 +00:00
|
|
|
*
|
|
|
|
* The filesystem should call this function in its inode constructor to
|
|
|
|
* indicate that the VFS can use large folios to cache the contents of
|
|
|
|
* the file.
|
|
|
|
*
|
|
|
|
* Context: This should not be called while the inode is active as it
|
|
|
|
* is non-atomic.
|
|
|
|
*/
|
|
|
|
static inline void mapping_set_large_folios(struct address_space *mapping)
|
|
|
|
{
|
2024-08-22 13:50:09 +00:00
|
|
|
mapping_set_folio_order_range(mapping, 0, MAX_PAGECACHE_ORDER);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int
|
|
|
|
mapping_max_folio_order(const struct address_space *mapping)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
|
|
|
|
return 0;
|
|
|
|
return (mapping->flags & AS_FOLIO_ORDER_MAX_MASK) >> AS_FOLIO_ORDER_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int
|
|
|
|
mapping_min_folio_order(const struct address_space *mapping)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
|
|
|
|
return 0;
|
|
|
|
return (mapping->flags & AS_FOLIO_ORDER_MIN_MASK) >> AS_FOLIO_ORDER_MIN;
|
2021-08-29 10:07:03 +00:00
|
|
|
}
|
|
|
|
|
2024-08-22 13:50:10 +00:00
|
|
|
static inline unsigned long
|
|
|
|
mapping_min_folio_nrpages(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return 1UL << mapping_min_folio_order(mapping);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mapping_align_index() - Align index for this mapping.
|
|
|
|
* @mapping: The address_space.
|
2024-08-27 08:42:07 +00:00
|
|
|
* @index: The page index.
|
2024-08-22 13:50:10 +00:00
|
|
|
*
|
|
|
|
* The index of a folio must be naturally aligned. If you are adding a
|
|
|
|
* new folio to the page cache and need to know what index to give it,
|
|
|
|
* call this function.
|
|
|
|
*/
|
|
|
|
static inline pgoff_t mapping_align_index(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return round_down(index, mapping_min_folio_nrpages(mapping));
|
2021-08-29 10:07:03 +00:00
|
|
|
}
|
|
|
|
|
2022-01-16 04:27:08 +00:00
|
|
|
/*
|
|
|
|
* Large folio support currently depends on THP. These dependencies are
|
|
|
|
* being worked on but are not yet fixed.
|
|
|
|
*/
|
2021-08-29 10:28:19 +00:00
|
|
|
static inline bool mapping_large_folio_support(struct address_space *mapping)
|
2020-10-16 03:06:00 +00:00
|
|
|
{
|
2024-08-22 13:50:09 +00:00
|
|
|
/* AS_FOLIO_ORDER is only reasonable for pagecache folios */
|
mm: huge_memory: fix misused mapping_large_folio_support() for anon folios
When I did a large folios split test, a WARNING "[ 5059.122759][ T166]
Cannot split file folio to non-0 order" was triggered. But the test cases
are only for anonmous folios. while mapping_large_folio_support() is only
reasonable for page cache folios.
In split_huge_page_to_list_to_order(), the folio passed to
mapping_large_folio_support() maybe anonmous folio. The folio_test_anon()
check is missing. So the split of the anonmous THP is failed. This is
also the same for shmem_mapping(). We'd better add a check for both. But
the shmem_mapping() in __split_huge_page() is not involved, as for
anonmous folios, the end parameter is set to -1, so (head[i].index >= end)
is always false. shmem_mapping() is not called.
Also add a VM_WARN_ON_ONCE() in mapping_large_folio_support() for anon
mapping, So we can detect the wrong use more easily.
THP folios maybe exist in the pagecache even the file system doesn't
support large folio, it is because when CONFIG_TRANSPARENT_HUGEPAGE is
enabled, khugepaged will try to collapse read-only file-backed pages to
THP. But the mapping does not actually support multi order large folios
properly.
Using /sys/kernel/debug/split_huge_pages to verify this, with this patch,
large anon THP is successfully split and the warning is ceased.
Link: https://lkml.kernel.org/r/202406071740485174hcFl7jRxncsHDtI-Pz-o@zte.com.cn
Fixes: c010d47f107f ("mm: thp: split huge page to any lower order pages")
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Ran Xiaokai <ran.xiaokai@zte.com.cn>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: xu xin <xu.xin16@zte.com.cn>
Cc: Yang Yang <yang.yang29@zte.com.cn>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-06-07 09:40:48 +00:00
|
|
|
VM_WARN_ONCE((unsigned long)mapping & PAGE_MAPPING_ANON,
|
|
|
|
"Anonymous mapping always supports large folio");
|
|
|
|
|
2024-08-22 13:50:09 +00:00
|
|
|
return mapping_max_folio_order(mapping) > 0;
|
2020-10-16 03:06:00 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 11:49:38 +00:00
|
|
|
/* Return the maximum folio size for this pagecache mapping, in bytes. */
|
2024-08-22 13:50:09 +00:00
|
|
|
static inline size_t mapping_max_folio_size(const struct address_space *mapping)
|
2024-05-21 11:49:38 +00:00
|
|
|
{
|
2024-08-22 13:50:09 +00:00
|
|
|
return PAGE_SIZE << mapping_max_folio_order(mapping);
|
2024-05-21 11:49:38 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 03:06:03 +00:00
|
|
|
static inline int filemap_nr_thps(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
|
|
|
|
return atomic_read(&mapping->nr_thps);
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void filemap_nr_thps_inc(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
|
2021-08-29 10:28:19 +00:00
|
|
|
if (!mapping_large_folio_support(mapping))
|
2020-10-16 03:06:03 +00:00
|
|
|
atomic_inc(&mapping->nr_thps);
|
|
|
|
#else
|
2020-10-10 15:47:55 +00:00
|
|
|
WARN_ON_ONCE(mapping_large_folio_support(mapping) == 0);
|
2020-10-16 03:06:03 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void filemap_nr_thps_dec(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
|
2021-08-29 10:28:19 +00:00
|
|
|
if (!mapping_large_folio_support(mapping))
|
2020-10-16 03:06:03 +00:00
|
|
|
atomic_dec(&mapping->nr_thps);
|
|
|
|
#else
|
2020-10-10 15:47:55 +00:00
|
|
|
WARN_ON_ONCE(mapping_large_folio_support(mapping) == 0);
|
2020-10-16 03:06:03 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
mm/util: Add folio_mapping() and folio_file_mapping()
These are the folio equivalent of page_mapping() and page_file_mapping().
Add an out-of-line page_mapping() wrapper around folio_mapping()
in order to prevent the page_folio() call from bloating every caller
of page_mapping(). Adjust page_file_mapping() and page_mapping_file()
to use folios internally. Rename __page_file_mapping() to
swapcache_mapping() and change it to take a folio.
This ends up saving 122 bytes of text overall. folio_mapping() is
45 bytes shorter than page_mapping() was, but the new page_mapping()
wrapper is 30 bytes. The major reduction is a few bytes less in dozens
of nfs functions (which call page_file_mapping()). Most of these appear
to be a slight change in gcc's register allocation decisions, which allow:
48 8b 56 08 mov 0x8(%rsi),%rdx
48 8d 42 ff lea -0x1(%rdx),%rax
83 e2 01 and $0x1,%edx
48 0f 44 c6 cmove %rsi,%rax
to become:
48 8b 46 08 mov 0x8(%rsi),%rax
48 8d 78 ff lea -0x1(%rax),%rdi
a8 01 test $0x1,%al
48 0f 44 fe cmove %rsi,%rdi
for a reduction of a single byte. Once the NFS client is converted to
use folios, this entire sequence will disappear.
Also add folio_mapping() documentation.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Reviewed-by: David Howells <dhowells@redhat.com>
2020-12-10 15:55:05 +00:00
|
|
|
struct address_space *folio_mapping(struct folio *);
|
|
|
|
struct address_space *swapcache_mapping(struct folio *);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* folio_file_mapping - Find the mapping this folio belongs to.
|
|
|
|
* @folio: The folio.
|
|
|
|
*
|
|
|
|
* For folios which are in the page cache, return the mapping that this
|
|
|
|
* page belongs to. Folios in the swap cache return the mapping of the
|
|
|
|
* swap file or swap device where the data is stored. This is different
|
|
|
|
* from the mapping returned by folio_mapping(). The only reason to
|
|
|
|
* use it is if, like NFS, you return 0 from ->activate_swapfile.
|
|
|
|
*
|
|
|
|
* Do not call this for folios which aren't in the page cache or swap cache.
|
|
|
|
*/
|
|
|
|
static inline struct address_space *folio_file_mapping(struct folio *folio)
|
|
|
|
{
|
|
|
|
if (unlikely(folio_test_swapcache(folio)))
|
|
|
|
return swapcache_mapping(folio);
|
|
|
|
|
|
|
|
return folio->mapping;
|
|
|
|
}
|
|
|
|
|
2023-08-02 15:13:32 +00:00
|
|
|
/**
|
|
|
|
* folio_flush_mapping - Find the file mapping this folio belongs to.
|
|
|
|
* @folio: The folio.
|
|
|
|
*
|
|
|
|
* For folios which are in the page cache, return the mapping that this
|
|
|
|
* page belongs to. Anonymous folios return NULL, even if they're in
|
|
|
|
* the swap cache. Other kinds of folio also return NULL.
|
|
|
|
*
|
|
|
|
* This is ONLY used by architecture cache flushing code. If you aren't
|
|
|
|
* writing cache flushing code, you want either folio_mapping() or
|
|
|
|
* folio_file_mapping().
|
2021-04-30 05:55:35 +00:00
|
|
|
*/
|
2023-08-02 15:13:32 +00:00
|
|
|
static inline struct address_space *folio_flush_mapping(struct folio *folio)
|
2021-04-30 05:55:35 +00:00
|
|
|
{
|
mm/util: Add folio_mapping() and folio_file_mapping()
These are the folio equivalent of page_mapping() and page_file_mapping().
Add an out-of-line page_mapping() wrapper around folio_mapping()
in order to prevent the page_folio() call from bloating every caller
of page_mapping(). Adjust page_file_mapping() and page_mapping_file()
to use folios internally. Rename __page_file_mapping() to
swapcache_mapping() and change it to take a folio.
This ends up saving 122 bytes of text overall. folio_mapping() is
45 bytes shorter than page_mapping() was, but the new page_mapping()
wrapper is 30 bytes. The major reduction is a few bytes less in dozens
of nfs functions (which call page_file_mapping()). Most of these appear
to be a slight change in gcc's register allocation decisions, which allow:
48 8b 56 08 mov 0x8(%rsi),%rdx
48 8d 42 ff lea -0x1(%rdx),%rax
83 e2 01 and $0x1,%edx
48 0f 44 c6 cmove %rsi,%rax
to become:
48 8b 46 08 mov 0x8(%rsi),%rax
48 8d 78 ff lea -0x1(%rax),%rdi
a8 01 test $0x1,%al
48 0f 44 fe cmove %rsi,%rdi
for a reduction of a single byte. Once the NFS client is converted to
use folios, this entire sequence will disappear.
Also add folio_mapping() documentation.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Reviewed-by: David Howells <dhowells@redhat.com>
2020-12-10 15:55:05 +00:00
|
|
|
if (unlikely(folio_test_swapcache(folio)))
|
2021-04-30 05:55:35 +00:00
|
|
|
return NULL;
|
2023-08-02 15:13:32 +00:00
|
|
|
|
mm/util: Add folio_mapping() and folio_file_mapping()
These are the folio equivalent of page_mapping() and page_file_mapping().
Add an out-of-line page_mapping() wrapper around folio_mapping()
in order to prevent the page_folio() call from bloating every caller
of page_mapping(). Adjust page_file_mapping() and page_mapping_file()
to use folios internally. Rename __page_file_mapping() to
swapcache_mapping() and change it to take a folio.
This ends up saving 122 bytes of text overall. folio_mapping() is
45 bytes shorter than page_mapping() was, but the new page_mapping()
wrapper is 30 bytes. The major reduction is a few bytes less in dozens
of nfs functions (which call page_file_mapping()). Most of these appear
to be a slight change in gcc's register allocation decisions, which allow:
48 8b 56 08 mov 0x8(%rsi),%rdx
48 8d 42 ff lea -0x1(%rdx),%rax
83 e2 01 and $0x1,%edx
48 0f 44 c6 cmove %rsi,%rax
to become:
48 8b 46 08 mov 0x8(%rsi),%rax
48 8d 78 ff lea -0x1(%rax),%rdi
a8 01 test $0x1,%al
48 0f 44 fe cmove %rsi,%rdi
for a reduction of a single byte. Once the NFS client is converted to
use folios, this entire sequence will disappear.
Also add folio_mapping() documentation.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Reviewed-by: David Howells <dhowells@redhat.com>
2020-12-10 15:55:05 +00:00
|
|
|
return folio_mapping(folio);
|
2021-04-30 05:55:35 +00:00
|
|
|
}
|
|
|
|
|
mm/util: Add folio_mapping() and folio_file_mapping()
These are the folio equivalent of page_mapping() and page_file_mapping().
Add an out-of-line page_mapping() wrapper around folio_mapping()
in order to prevent the page_folio() call from bloating every caller
of page_mapping(). Adjust page_file_mapping() and page_mapping_file()
to use folios internally. Rename __page_file_mapping() to
swapcache_mapping() and change it to take a folio.
This ends up saving 122 bytes of text overall. folio_mapping() is
45 bytes shorter than page_mapping() was, but the new page_mapping()
wrapper is 30 bytes. The major reduction is a few bytes less in dozens
of nfs functions (which call page_file_mapping()). Most of these appear
to be a slight change in gcc's register allocation decisions, which allow:
48 8b 56 08 mov 0x8(%rsi),%rdx
48 8d 42 ff lea -0x1(%rdx),%rax
83 e2 01 and $0x1,%edx
48 0f 44 c6 cmove %rsi,%rax
to become:
48 8b 46 08 mov 0x8(%rsi),%rax
48 8d 78 ff lea -0x1(%rax),%rdi
a8 01 test $0x1,%al
48 0f 44 fe cmove %rsi,%rdi
for a reduction of a single byte. Once the NFS client is converted to
use folios, this entire sequence will disappear.
Also add folio_mapping() documentation.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Reviewed-by: David Howells <dhowells@redhat.com>
2020-12-10 15:55:05 +00:00
|
|
|
static inline struct address_space *page_file_mapping(struct page *page)
|
|
|
|
{
|
|
|
|
return folio_file_mapping(page_folio(page));
|
2021-04-30 05:55:35 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 21:09:57 +00:00
|
|
|
/**
|
|
|
|
* folio_inode - Get the host inode for this folio.
|
|
|
|
* @folio: The folio.
|
|
|
|
*
|
|
|
|
* For folios which are in the page cache, return the inode that this folio
|
|
|
|
* belongs to.
|
|
|
|
*
|
|
|
|
* Do not call this for folios which aren't in the page cache.
|
|
|
|
*/
|
|
|
|
static inline struct inode *folio_inode(struct folio *folio)
|
|
|
|
{
|
|
|
|
return folio->mapping->host;
|
|
|
|
}
|
|
|
|
|
2020-06-02 04:47:38 +00:00
|
|
|
/**
|
2021-01-11 15:04:40 +00:00
|
|
|
* folio_attach_private - Attach private data to a folio.
|
|
|
|
* @folio: Folio to attach data to.
|
|
|
|
* @data: Data to attach to folio.
|
2020-06-02 04:47:38 +00:00
|
|
|
*
|
2021-01-11 15:04:40 +00:00
|
|
|
* Attaching private data to a folio increments the page's reference count.
|
|
|
|
* The data must be detached before the folio will be freed.
|
2020-06-02 04:47:38 +00:00
|
|
|
*/
|
2021-01-11 15:04:40 +00:00
|
|
|
static inline void folio_attach_private(struct folio *folio, void *data)
|
2020-06-02 04:47:38 +00:00
|
|
|
{
|
2021-01-11 15:04:40 +00:00
|
|
|
folio_get(folio);
|
|
|
|
folio->private = data;
|
|
|
|
folio_set_private(folio);
|
2020-06-02 04:47:38 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 20:54:58 +00:00
|
|
|
/**
|
|
|
|
* folio_change_private - Change private data on a folio.
|
|
|
|
* @folio: Folio to change the data on.
|
|
|
|
* @data: Data to set on the folio.
|
|
|
|
*
|
|
|
|
* Change the private data attached to a folio and return the old
|
|
|
|
* data. The page must previously have had data attached and the data
|
|
|
|
* must be detached before the folio will be freed.
|
|
|
|
*
|
|
|
|
* Return: Data that was previously attached to the folio.
|
|
|
|
*/
|
|
|
|
static inline void *folio_change_private(struct folio *folio, void *data)
|
|
|
|
{
|
|
|
|
void *old = folio_get_private(folio);
|
|
|
|
|
|
|
|
folio->private = data;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2020-06-02 04:47:38 +00:00
|
|
|
/**
|
2021-01-11 15:04:40 +00:00
|
|
|
* folio_detach_private - Detach private data from a folio.
|
|
|
|
* @folio: Folio to detach data from.
|
2020-06-02 04:47:38 +00:00
|
|
|
*
|
2021-01-11 15:04:40 +00:00
|
|
|
* Removes the data that was previously attached to the folio and decrements
|
2020-06-02 04:47:38 +00:00
|
|
|
* the refcount on the page.
|
|
|
|
*
|
2021-01-11 15:04:40 +00:00
|
|
|
* Return: Data that was attached to the folio.
|
2020-06-02 04:47:38 +00:00
|
|
|
*/
|
2021-01-11 15:04:40 +00:00
|
|
|
static inline void *folio_detach_private(struct folio *folio)
|
2020-06-02 04:47:38 +00:00
|
|
|
{
|
2021-01-11 15:04:40 +00:00
|
|
|
void *data = folio_get_private(folio);
|
2020-06-02 04:47:38 +00:00
|
|
|
|
2021-01-11 15:04:40 +00:00
|
|
|
if (!folio_test_private(folio))
|
2020-06-02 04:47:38 +00:00
|
|
|
return NULL;
|
2021-01-11 15:04:40 +00:00
|
|
|
folio_clear_private(folio);
|
|
|
|
folio->private = NULL;
|
|
|
|
folio_put(folio);
|
2020-06-02 04:47:38 +00:00
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-01-11 15:04:40 +00:00
|
|
|
static inline void attach_page_private(struct page *page, void *data)
|
|
|
|
{
|
|
|
|
folio_attach_private(page_folio(page), data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void *detach_page_private(struct page *page)
|
|
|
|
{
|
|
|
|
return folio_detach_private(page_folio(page));
|
|
|
|
}
|
|
|
|
|
2006-03-24 11:16:04 +00:00
|
|
|
#ifdef CONFIG_NUMA
|
2024-03-21 16:36:40 +00:00
|
|
|
struct folio *filemap_alloc_folio_noprof(gfp_t gfp, unsigned int order);
|
2006-03-24 11:16:04 +00:00
|
|
|
#else
|
2024-03-21 16:36:40 +00:00
|
|
|
static inline struct folio *filemap_alloc_folio_noprof(gfp_t gfp, unsigned int order)
|
2006-10-28 17:38:23 +00:00
|
|
|
{
|
2024-03-21 16:36:40 +00:00
|
|
|
return folio_alloc_noprof(gfp, order);
|
2006-10-28 17:38:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-03-21 16:36:40 +00:00
|
|
|
#define filemap_alloc_folio(...) \
|
|
|
|
alloc_hooks(filemap_alloc_folio_noprof(__VA_ARGS__))
|
|
|
|
|
2020-12-16 04:11:07 +00:00
|
|
|
static inline struct page *__page_cache_alloc(gfp_t gfp)
|
|
|
|
{
|
|
|
|
return &filemap_alloc_folio(gfp, 0)->page;
|
|
|
|
}
|
|
|
|
|
2016-07-26 22:24:53 +00:00
|
|
|
static inline gfp_t readahead_gfp_mask(struct address_space *x)
|
2011-05-25 00:12:25 +00:00
|
|
|
{
|
2017-11-16 01:38:03 +00:00
|
|
|
return mapping_gfp_mask(x) | __GFP_NORETRY | __GFP_NOWARN;
|
2011-05-25 00:12:25 +00:00
|
|
|
}
|
|
|
|
|
2022-05-02 01:39:29 +00:00
|
|
|
typedef int filler_t(struct file *, struct folio *);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2017-11-21 19:07:06 +00:00
|
|
|
pgoff_t page_cache_next_miss(struct address_space *mapping,
|
2014-04-03 21:47:44 +00:00
|
|
|
pgoff_t index, unsigned long max_scan);
|
2017-11-21 19:07:06 +00:00
|
|
|
pgoff_t page_cache_prev_miss(struct address_space *mapping,
|
2014-04-03 21:47:44 +00:00
|
|
|
pgoff_t index, unsigned long max_scan);
|
|
|
|
|
2023-05-26 20:43:23 +00:00
|
|
|
/**
|
|
|
|
* typedef fgf_t - Flags for getting folios from the page cache.
|
|
|
|
*
|
|
|
|
* Most users of the page cache will not need to use these flags;
|
|
|
|
* there are convenience functions such as filemap_get_folio() and
|
|
|
|
* filemap_lock_folio(). For users which need more control over exactly
|
|
|
|
* what is done with the folios, these flags to __filemap_get_folio()
|
|
|
|
* are available.
|
|
|
|
*
|
|
|
|
* * %FGP_ACCESSED - The folio will be marked accessed.
|
|
|
|
* * %FGP_LOCK - The folio is returned locked.
|
|
|
|
* * %FGP_CREAT - If no folio is present then a new folio is allocated,
|
|
|
|
* added to the page cache and the VM's LRU list. The folio is
|
|
|
|
* returned locked.
|
|
|
|
* * %FGP_FOR_MMAP - The caller wants to do its own locking dance if the
|
|
|
|
* folio is already in cache. If the folio was allocated, unlock it
|
|
|
|
* before returning so the caller can do the same dance.
|
|
|
|
* * %FGP_WRITE - The folio will be written to by the caller.
|
|
|
|
* * %FGP_NOFS - __GFP_FS will get cleared in gfp.
|
|
|
|
* * %FGP_NOWAIT - Don't block on the folio lock.
|
|
|
|
* * %FGP_STABLE - Wait for the folio to be stable (finished writeback)
|
|
|
|
* * %FGP_WRITEBEGIN - The flags to use in a filesystem write_begin()
|
|
|
|
* implementation.
|
|
|
|
*/
|
|
|
|
typedef unsigned int __bitwise fgf_t;
|
|
|
|
|
|
|
|
#define FGP_ACCESSED ((__force fgf_t)0x00000001)
|
|
|
|
#define FGP_LOCK ((__force fgf_t)0x00000002)
|
|
|
|
#define FGP_CREAT ((__force fgf_t)0x00000004)
|
|
|
|
#define FGP_WRITE ((__force fgf_t)0x00000008)
|
|
|
|
#define FGP_NOFS ((__force fgf_t)0x00000010)
|
|
|
|
#define FGP_NOWAIT ((__force fgf_t)0x00000020)
|
|
|
|
#define FGP_FOR_MMAP ((__force fgf_t)0x00000040)
|
|
|
|
#define FGP_STABLE ((__force fgf_t)0x00000080)
|
2023-05-19 20:10:37 +00:00
|
|
|
#define FGF_GET_ORDER(fgf) (((__force unsigned)fgf) >> 26) /* top 6 bits */
|
2014-06-04 23:10:31 +00:00
|
|
|
|
2023-03-24 18:01:01 +00:00
|
|
|
#define FGP_WRITEBEGIN (FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE)
|
|
|
|
|
mm: factor out the order calculation into a new helper
Patch series "Support large folios for tmpfs", v3.
Traditionally, tmpfs only supported PMD-sized large folios. However
nowadays with other file systems supporting any sized large folios, and
extending anonymous to support mTHP, we should not restrict tmpfs to
allocating only PMD-sized large folios, making it more special. Instead,
we should allow tmpfs can allocate any sized large folios.
Considering that tmpfs already has the 'huge=' option to control the
PMD-sized large folios allocation, we can extend the 'huge=' option to
allow any sized large folios. The semantics of the 'huge=' mount option
are:
huge=never: no any sized large folios
huge=always: any sized large folios
huge=within_size: like 'always' but respect the i_size
huge=advise: like 'always' if requested with madvise()
Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
allocate the PMD-sized large folios if huge=always/within_size/advise is
set.
Moreover, the 'deny' and 'force' testing options controlled by
'/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
semantics. The 'deny' can disable any sized large folios for tmpfs, while
the 'force' can enable PMD sized large folios for tmpfs.
This patch (of 6):
Factor out the order calculation into a new helper, which can be reused by
shmem in the following patch.
Link: https://lkml.kernel.org/r/cover.1732779148.git.baolin.wang@linux.alibaba.com
Link: https://lkml.kernel.org/r/5505f9ea50942820c1924d1803bfdd3a524e54f6.1732779148.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Suggested-by: Matthew Wilcox <willy@infradead.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Lance Yang <ioworker0@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-28 07:40:39 +00:00
|
|
|
static inline unsigned int filemap_get_order(size_t size)
|
|
|
|
{
|
|
|
|
unsigned int shift = ilog2(size);
|
|
|
|
|
|
|
|
if (shift <= PAGE_SHIFT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return shift - PAGE_SHIFT;
|
|
|
|
}
|
|
|
|
|
2023-05-19 20:10:37 +00:00
|
|
|
/**
|
|
|
|
* fgf_set_order - Encode a length in the fgf_t flags.
|
|
|
|
* @size: The suggested size of the folio to create.
|
|
|
|
*
|
|
|
|
* The caller of __filemap_get_folio() can use this to suggest a preferred
|
|
|
|
* size for the folio that is created. If there is already a folio at
|
|
|
|
* the index, it will be returned, no matter what its size. If a folio
|
|
|
|
* is freshly created, it may be of a different size than requested
|
|
|
|
* due to alignment constraints, memory pressure, or the presence of
|
|
|
|
* other folios at nearby indices.
|
|
|
|
*/
|
|
|
|
static inline fgf_t fgf_set_order(size_t size)
|
|
|
|
{
|
mm: factor out the order calculation into a new helper
Patch series "Support large folios for tmpfs", v3.
Traditionally, tmpfs only supported PMD-sized large folios. However
nowadays with other file systems supporting any sized large folios, and
extending anonymous to support mTHP, we should not restrict tmpfs to
allocating only PMD-sized large folios, making it more special. Instead,
we should allow tmpfs can allocate any sized large folios.
Considering that tmpfs already has the 'huge=' option to control the
PMD-sized large folios allocation, we can extend the 'huge=' option to
allow any sized large folios. The semantics of the 'huge=' mount option
are:
huge=never: no any sized large folios
huge=always: any sized large folios
huge=within_size: like 'always' but respect the i_size
huge=advise: like 'always' if requested with madvise()
Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
allocate the PMD-sized large folios if huge=always/within_size/advise is
set.
Moreover, the 'deny' and 'force' testing options controlled by
'/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
semantics. The 'deny' can disable any sized large folios for tmpfs, while
the 'force' can enable PMD sized large folios for tmpfs.
This patch (of 6):
Factor out the order calculation into a new helper, which can be reused by
shmem in the following patch.
Link: https://lkml.kernel.org/r/cover.1732779148.git.baolin.wang@linux.alibaba.com
Link: https://lkml.kernel.org/r/5505f9ea50942820c1924d1803bfdd3a524e54f6.1732779148.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Suggested-by: Matthew Wilcox <willy@infradead.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Lance Yang <ioworker0@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-28 07:40:39 +00:00
|
|
|
unsigned int order = filemap_get_order(size);
|
2023-05-19 20:10:37 +00:00
|
|
|
|
mm: factor out the order calculation into a new helper
Patch series "Support large folios for tmpfs", v3.
Traditionally, tmpfs only supported PMD-sized large folios. However
nowadays with other file systems supporting any sized large folios, and
extending anonymous to support mTHP, we should not restrict tmpfs to
allocating only PMD-sized large folios, making it more special. Instead,
we should allow tmpfs can allocate any sized large folios.
Considering that tmpfs already has the 'huge=' option to control the
PMD-sized large folios allocation, we can extend the 'huge=' option to
allow any sized large folios. The semantics of the 'huge=' mount option
are:
huge=never: no any sized large folios
huge=always: any sized large folios
huge=within_size: like 'always' but respect the i_size
huge=advise: like 'always' if requested with madvise()
Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
allocate the PMD-sized large folios if huge=always/within_size/advise is
set.
Moreover, the 'deny' and 'force' testing options controlled by
'/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
semantics. The 'deny' can disable any sized large folios for tmpfs, while
the 'force' can enable PMD sized large folios for tmpfs.
This patch (of 6):
Factor out the order calculation into a new helper, which can be reused by
shmem in the following patch.
Link: https://lkml.kernel.org/r/cover.1732779148.git.baolin.wang@linux.alibaba.com
Link: https://lkml.kernel.org/r/5505f9ea50942820c1924d1803bfdd3a524e54f6.1732779148.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Suggested-by: Matthew Wilcox <willy@infradead.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Lance Yang <ioworker0@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-28 07:40:39 +00:00
|
|
|
if (!order)
|
2023-05-19 20:10:37 +00:00
|
|
|
return 0;
|
mm: factor out the order calculation into a new helper
Patch series "Support large folios for tmpfs", v3.
Traditionally, tmpfs only supported PMD-sized large folios. However
nowadays with other file systems supporting any sized large folios, and
extending anonymous to support mTHP, we should not restrict tmpfs to
allocating only PMD-sized large folios, making it more special. Instead,
we should allow tmpfs can allocate any sized large folios.
Considering that tmpfs already has the 'huge=' option to control the
PMD-sized large folios allocation, we can extend the 'huge=' option to
allow any sized large folios. The semantics of the 'huge=' mount option
are:
huge=never: no any sized large folios
huge=always: any sized large folios
huge=within_size: like 'always' but respect the i_size
huge=advise: like 'always' if requested with madvise()
Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
allocate the PMD-sized large folios if huge=always/within_size/advise is
set.
Moreover, the 'deny' and 'force' testing options controlled by
'/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
semantics. The 'deny' can disable any sized large folios for tmpfs, while
the 'force' can enable PMD sized large folios for tmpfs.
This patch (of 6):
Factor out the order calculation into a new helper, which can be reused by
shmem in the following patch.
Link: https://lkml.kernel.org/r/cover.1732779148.git.baolin.wang@linux.alibaba.com
Link: https://lkml.kernel.org/r/5505f9ea50942820c1924d1803bfdd3a524e54f6.1732779148.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Suggested-by: Matthew Wilcox <willy@infradead.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Lance Yang <ioworker0@gmail.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2024-11-28 07:40:39 +00:00
|
|
|
return (__force fgf_t)(order << 26);
|
2023-05-19 20:10:37 +00:00
|
|
|
}
|
|
|
|
|
2023-03-07 14:34:05 +00:00
|
|
|
void *filemap_get_entry(struct address_space *mapping, pgoff_t index);
|
2021-03-08 16:45:35 +00:00
|
|
|
struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
|
2023-05-26 20:43:23 +00:00
|
|
|
fgf_t fgp_flags, gfp_t gfp);
|
2021-03-08 16:45:35 +00:00
|
|
|
struct page *pagecache_get_page(struct address_space *mapping, pgoff_t index,
|
2023-05-26 20:43:23 +00:00
|
|
|
fgf_t fgp_flags, gfp_t gfp);
|
2021-03-08 16:45:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_get_folio - Find and get a folio.
|
|
|
|
* @mapping: The address_space to search.
|
|
|
|
* @index: The page index.
|
|
|
|
*
|
|
|
|
* Looks up the page cache entry at @mapping & @index. If a folio is
|
|
|
|
* present, it is returned with an increased refcount.
|
|
|
|
*
|
2023-03-07 14:34:10 +00:00
|
|
|
* Return: A folio or ERR_PTR(-ENOENT) if there is no folio in the cache for
|
|
|
|
* this index. Will not return a shadow, swap or DAX entry.
|
2021-03-08 16:45:35 +00:00
|
|
|
*/
|
|
|
|
static inline struct folio *filemap_get_folio(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return __filemap_get_folio(mapping, index, 0, 0);
|
|
|
|
}
|
2014-06-04 23:10:31 +00:00
|
|
|
|
2022-02-09 20:21:43 +00:00
|
|
|
/**
|
|
|
|
* filemap_lock_folio - Find and lock a folio.
|
|
|
|
* @mapping: The address_space to search.
|
|
|
|
* @index: The page index.
|
|
|
|
*
|
|
|
|
* Looks up the page cache entry at @mapping & @index. If a folio is
|
|
|
|
* present, it is returned locked with an increased refcount.
|
|
|
|
*
|
|
|
|
* Context: May sleep.
|
2023-03-07 14:34:10 +00:00
|
|
|
* Return: A folio or ERR_PTR(-ENOENT) if there is no folio in the cache for
|
|
|
|
* this index. Will not return a shadow, swap or DAX entry.
|
2022-02-09 20:21:43 +00:00
|
|
|
*/
|
|
|
|
static inline struct folio *filemap_lock_folio(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return __filemap_get_folio(mapping, index, FGP_LOCK, 0);
|
|
|
|
}
|
|
|
|
|
2023-01-04 21:14:26 +00:00
|
|
|
/**
|
|
|
|
* filemap_grab_folio - grab a folio from the page cache
|
|
|
|
* @mapping: The address space to search
|
|
|
|
* @index: The page index
|
|
|
|
*
|
|
|
|
* Looks up the page cache entry at @mapping & @index. If no folio is found,
|
|
|
|
* a new folio is created. The folio is locked, marked as accessed, and
|
|
|
|
* returned.
|
|
|
|
*
|
2023-03-07 14:34:10 +00:00
|
|
|
* Return: A found or created folio. ERR_PTR(-ENOMEM) if no folio is found
|
|
|
|
* and failed to create a folio.
|
2023-01-04 21:14:26 +00:00
|
|
|
*/
|
|
|
|
static inline struct folio *filemap_grab_folio(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return __filemap_get_folio(mapping, index,
|
|
|
|
FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
|
|
|
|
mapping_gfp_mask(mapping));
|
|
|
|
}
|
|
|
|
|
2014-06-04 23:10:31 +00:00
|
|
|
/**
|
|
|
|
* find_get_page - find and get a page reference
|
|
|
|
* @mapping: the address_space to search
|
|
|
|
* @offset: the page index
|
|
|
|
*
|
|
|
|
* Looks up the page cache slot at @mapping & @offset. If there is a
|
|
|
|
* page cache page, it is returned with an increased refcount.
|
|
|
|
*
|
|
|
|
* Otherwise, %NULL is returned.
|
|
|
|
*/
|
|
|
|
static inline struct page *find_get_page(struct address_space *mapping,
|
|
|
|
pgoff_t offset)
|
|
|
|
{
|
2014-12-29 19:30:35 +00:00
|
|
|
return pagecache_get_page(mapping, offset, 0, 0);
|
2014-06-04 23:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct page *find_get_page_flags(struct address_space *mapping,
|
2023-05-26 20:43:23 +00:00
|
|
|
pgoff_t offset, fgf_t fgp_flags)
|
2014-06-04 23:10:31 +00:00
|
|
|
{
|
2014-12-29 19:30:35 +00:00
|
|
|
return pagecache_get_page(mapping, offset, fgp_flags, 0);
|
2014-06-04 23:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* find_lock_page - locate, pin and lock a pagecache page
|
|
|
|
* @mapping: the address_space to search
|
2020-10-27 09:51:17 +00:00
|
|
|
* @index: the page index
|
2014-06-04 23:10:31 +00:00
|
|
|
*
|
2020-10-27 09:51:17 +00:00
|
|
|
* Looks up the page cache entry at @mapping & @index. If there is a
|
2014-06-04 23:10:31 +00:00
|
|
|
* page cache page, it is returned locked and with an increased
|
|
|
|
* refcount.
|
|
|
|
*
|
2020-10-13 23:51:41 +00:00
|
|
|
* Context: May sleep.
|
|
|
|
* Return: A struct page or %NULL if there is no page in the cache for this
|
|
|
|
* index.
|
2014-06-04 23:10:31 +00:00
|
|
|
*/
|
|
|
|
static inline struct page *find_lock_page(struct address_space *mapping,
|
2020-10-13 23:51:41 +00:00
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return pagecache_get_page(mapping, index, FGP_LOCK, 0);
|
|
|
|
}
|
|
|
|
|
2014-06-04 23:10:31 +00:00
|
|
|
/**
|
|
|
|
* find_or_create_page - locate or add a pagecache page
|
|
|
|
* @mapping: the page's address_space
|
|
|
|
* @index: the page's index into the mapping
|
|
|
|
* @gfp_mask: page allocation mode
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* If the page is not present, a new page is allocated using @gfp_mask
|
|
|
|
* and added to the page cache and the VM's LRU list. The page is
|
|
|
|
* returned locked and with an increased refcount.
|
|
|
|
*
|
|
|
|
* On memory exhaustion, %NULL is returned.
|
|
|
|
*
|
|
|
|
* find_or_create_page() may sleep, even if @gfp_flags specifies an
|
|
|
|
* atomic allocation!
|
|
|
|
*/
|
|
|
|
static inline struct page *find_or_create_page(struct address_space *mapping,
|
2020-04-02 04:07:55 +00:00
|
|
|
pgoff_t index, gfp_t gfp_mask)
|
2014-06-04 23:10:31 +00:00
|
|
|
{
|
2020-04-02 04:07:55 +00:00
|
|
|
return pagecache_get_page(mapping, index,
|
2014-06-04 23:10:31 +00:00
|
|
|
FGP_LOCK|FGP_ACCESSED|FGP_CREAT,
|
2014-12-29 19:30:35 +00:00
|
|
|
gfp_mask);
|
2014-06-04 23:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* grab_cache_page_nowait - returns locked page at given index in given cache
|
|
|
|
* @mapping: target address_space
|
|
|
|
* @index: the page index
|
|
|
|
*
|
|
|
|
* Same as grab_cache_page(), but do not wait if the page is unavailable.
|
|
|
|
* This is intended for speculative data generators, where the data can
|
|
|
|
* be regenerated if the page couldn't be grabbed. This routine should
|
|
|
|
* be safe to call while holding the lock for another page.
|
|
|
|
*
|
|
|
|
* Clear __GFP_FS when allocating the page to avoid recursion into the fs
|
|
|
|
* and deadlock against the caller's locked page.
|
|
|
|
*/
|
|
|
|
static inline struct page *grab_cache_page_nowait(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
|
|
|
{
|
|
|
|
return pagecache_get_page(mapping, index,
|
|
|
|
FGP_LOCK|FGP_CREAT|FGP_NOFS|FGP_NOWAIT,
|
2014-12-29 19:30:35 +00:00
|
|
|
mapping_gfp_mask(mapping));
|
2014-06-04 23:10:31 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 17:58:52 +00:00
|
|
|
extern pgoff_t __folio_swap_cache_index(struct folio *folio);
|
2021-01-16 04:39:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* folio_index - File index of a folio.
|
|
|
|
* @folio: The folio.
|
|
|
|
*
|
|
|
|
* For a folio which is either in the page cache or the swap cache,
|
|
|
|
* return its index within the address_space it belongs to. If you know
|
|
|
|
* the page is definitely in the page cache, you can look at the folio's
|
|
|
|
* index directly.
|
|
|
|
*
|
|
|
|
* Return: The index (offset in units of pages) of a folio in its file.
|
|
|
|
*/
|
|
|
|
static inline pgoff_t folio_index(struct folio *folio)
|
|
|
|
{
|
2024-05-21 17:58:52 +00:00
|
|
|
if (unlikely(folio_test_swapcache(folio)))
|
|
|
|
return __folio_swap_cache_index(folio);
|
|
|
|
return folio->index;
|
2021-01-16 04:39:21 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 20:24:31 +00:00
|
|
|
/**
|
|
|
|
* folio_next_index - Get the index of the next folio.
|
|
|
|
* @folio: The current folio.
|
|
|
|
*
|
|
|
|
* Return: The index of the folio which follows this folio in the file.
|
|
|
|
*/
|
|
|
|
static inline pgoff_t folio_next_index(struct folio *folio)
|
|
|
|
{
|
|
|
|
return folio->index + folio_nr_pages(folio);
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:39:21 +00:00
|
|
|
/**
|
|
|
|
* folio_file_page - The page for a particular index.
|
|
|
|
* @folio: The folio which contains this index.
|
|
|
|
* @index: The index we want to look up.
|
|
|
|
*
|
|
|
|
* Sometimes after looking up a folio in the page cache, we need to
|
|
|
|
* obtain the specific page for an index (eg a page fault).
|
|
|
|
*
|
|
|
|
* Return: The page containing the file data for this index.
|
|
|
|
*/
|
|
|
|
static inline struct page *folio_file_page(struct folio *folio, pgoff_t index)
|
|
|
|
{
|
|
|
|
return folio_page(folio, index & (folio_nr_pages(folio) - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* folio_contains - Does this folio contain this index?
|
|
|
|
* @folio: The folio.
|
|
|
|
* @index: The page index within the file.
|
|
|
|
*
|
|
|
|
* Context: The caller should have the page locked in order to prevent
|
|
|
|
* (eg) shmem from moving the page between the page cache and swap cache
|
|
|
|
* and changing its index in the middle of the operation.
|
|
|
|
* Return: true or false.
|
|
|
|
*/
|
|
|
|
static inline bool folio_contains(struct folio *folio, pgoff_t index)
|
|
|
|
{
|
|
|
|
return index - folio_index(folio) < folio_nr_pages(folio);
|
|
|
|
}
|
|
|
|
|
2020-04-02 04:04:57 +00:00
|
|
|
/*
|
|
|
|
* Given the page we found in the page cache, return the page corresponding
|
|
|
|
* to this index in the file
|
|
|
|
*/
|
|
|
|
static inline struct page *find_subpage(struct page *head, pgoff_t index)
|
2019-09-23 22:34:52 +00:00
|
|
|
{
|
2020-04-02 04:04:57 +00:00
|
|
|
/* HugeTLBfs wants the head page regardless */
|
|
|
|
if (PageHuge(head))
|
|
|
|
return head;
|
2019-09-23 22:34:52 +00:00
|
|
|
|
2020-08-15 00:30:37 +00:00
|
|
|
return head + (index & (thp_nr_pages(head) - 1));
|
2019-09-23 22:34:52 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:30:25 +00:00
|
|
|
unsigned filemap_get_folios(struct address_space *mapping, pgoff_t *start,
|
|
|
|
pgoff_t end, struct folio_batch *fbatch);
|
2022-08-24 00:40:17 +00:00
|
|
|
unsigned filemap_get_folios_contig(struct address_space *mapping,
|
|
|
|
pgoff_t *start, pgoff_t end, struct folio_batch *fbatch);
|
2023-01-04 21:14:27 +00:00
|
|
|
unsigned filemap_get_folios_tag(struct address_space *mapping, pgoff_t *start,
|
|
|
|
pgoff_t end, xa_mark_t tag, struct folio_batch *fbatch);
|
2005-04-16 22:20:36 +00: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-04 20:00:53 +00:00
|
|
|
struct page *grab_cache_page_write_begin(struct address_space *mapping,
|
2022-02-22 16:25:12 +00:00
|
|
|
pgoff_t index);
|
2007-10-16 08:25:01 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Returns locked page at given index in given cache, creating it if needed.
|
|
|
|
*/
|
2007-10-16 08:24:37 +00:00
|
|
|
static inline struct page *grab_cache_page(struct address_space *mapping,
|
|
|
|
pgoff_t index)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
return find_or_create_page(mapping, index, mapping_gfp_mask(mapping));
|
|
|
|
}
|
|
|
|
|
2020-12-16 16:45:30 +00:00
|
|
|
struct folio *read_cache_folio(struct address_space *, pgoff_t index,
|
2022-05-02 01:39:29 +00:00
|
|
|
filler_t *filler, struct file *file);
|
2023-02-06 16:25:19 +00:00
|
|
|
struct folio *mapping_read_folio_gfp(struct address_space *, pgoff_t index,
|
|
|
|
gfp_t flags);
|
2020-12-16 16:45:30 +00:00
|
|
|
struct page *read_cache_page(struct address_space *, pgoff_t index,
|
2022-05-02 01:39:29 +00:00
|
|
|
filler_t *filler, struct file *file);
|
2010-01-27 17:20:03 +00:00
|
|
|
extern struct page * read_cache_page_gfp(struct address_space *mapping,
|
|
|
|
pgoff_t index, gfp_t gfp_mask);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-06-23 09:05:08 +00:00
|
|
|
static inline struct page *read_mapping_page(struct address_space *mapping,
|
2022-02-09 20:21:23 +00:00
|
|
|
pgoff_t index, struct file *file)
|
2006-06-23 09:05:08 +00:00
|
|
|
{
|
2022-02-09 20:21:23 +00:00
|
|
|
return read_cache_page(mapping, index, NULL, file);
|
2006-06-23 09:05:08 +00:00
|
|
|
}
|
|
|
|
|
2020-12-16 16:45:30 +00:00
|
|
|
static inline struct folio *read_mapping_folio(struct address_space *mapping,
|
2022-02-09 20:21:23 +00:00
|
|
|
pgoff_t index, struct file *file)
|
2020-12-16 16:45:30 +00:00
|
|
|
{
|
2022-02-09 20:21:23 +00:00
|
|
|
return read_cache_folio(mapping, index, NULL, file);
|
2020-12-16 16:45:30 +00:00
|
|
|
}
|
|
|
|
|
2024-10-05 20:01:12 +00:00
|
|
|
/**
|
|
|
|
* page_pgoff - Calculate the logical page offset of this page.
|
|
|
|
* @folio: The folio containing this page.
|
|
|
|
* @page: The page which we need the offset of.
|
|
|
|
*
|
|
|
|
* For file pages, this is the offset from the beginning of the file
|
|
|
|
* in units of PAGE_SIZE. For anonymous pages, this is the offset from
|
|
|
|
* the beginning of the anon_vma in units of PAGE_SIZE. This will
|
|
|
|
* return nonsense for KSM pages.
|
|
|
|
*
|
|
|
|
* Context: Caller must have a reference on the folio or otherwise
|
|
|
|
* prevent it from being split or freed.
|
|
|
|
*
|
|
|
|
* Return: The offset in units of PAGE_SIZE.
|
2014-07-23 21:00:01 +00:00
|
|
|
*/
|
2024-10-05 20:01:12 +00:00
|
|
|
static inline pgoff_t page_pgoff(const struct folio *folio,
|
|
|
|
const struct page *page)
|
2014-07-23 21:00:01 +00:00
|
|
|
{
|
2024-10-05 20:01:12 +00:00
|
|
|
return folio->index + folio_page_idx(folio, page);
|
2014-07-23 21:00:01 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Return byte-offset into filesystem object for page.
|
|
|
|
*/
|
|
|
|
static inline loff_t page_offset(struct page *page)
|
|
|
|
{
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 12:29:47 +00:00
|
|
|
return ((loff_t)page->index) << PAGE_SHIFT;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2020-12-24 12:25:19 +00:00
|
|
|
/**
|
|
|
|
* folio_pos - Returns the byte position of this folio in its file.
|
|
|
|
* @folio: The folio.
|
|
|
|
*/
|
|
|
|
static inline loff_t folio_pos(struct folio *folio)
|
|
|
|
{
|
|
|
|
return page_offset(&folio->page);
|
|
|
|
}
|
|
|
|
|
2022-02-03 04:29:45 +00:00
|
|
|
/*
|
|
|
|
* Get the offset in PAGE_SIZE (even for hugetlb folios).
|
|
|
|
*/
|
|
|
|
static inline pgoff_t folio_pgoff(struct folio *folio)
|
|
|
|
{
|
|
|
|
return folio->index;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
|
|
|
|
unsigned long address)
|
|
|
|
{
|
2010-05-28 00:29:16 +00:00
|
|
|
pgoff_t pgoff;
|
|
|
|
pgoff = (address - vma->vm_start) >> PAGE_SHIFT;
|
2005-04-16 22:20:36 +00:00
|
|
|
pgoff += vma->vm_pgoff;
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 12:29:47 +00:00
|
|
|
return pgoff;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-23 14:22:14 +00:00
|
|
|
struct wait_page_key {
|
2021-01-16 16:22:14 +00:00
|
|
|
struct folio *folio;
|
2020-05-23 14:22:14 +00:00
|
|
|
int bit_nr;
|
|
|
|
int page_match;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct wait_page_queue {
|
2021-01-16 16:22:14 +00:00
|
|
|
struct folio *folio;
|
2020-05-23 14:22:14 +00:00
|
|
|
int bit_nr;
|
|
|
|
wait_queue_entry_t wait;
|
|
|
|
};
|
|
|
|
|
2020-08-03 20:01:22 +00:00
|
|
|
static inline bool wake_page_match(struct wait_page_queue *wait_page,
|
2020-05-23 14:22:14 +00:00
|
|
|
struct wait_page_key *key)
|
|
|
|
{
|
2021-01-16 16:22:14 +00:00
|
|
|
if (wait_page->folio != key->folio)
|
2020-08-03 20:01:22 +00:00
|
|
|
return false;
|
2020-05-23 14:22:14 +00:00
|
|
|
key->page_match = 1;
|
|
|
|
|
|
|
|
if (wait_page->bit_nr != key->bit_nr)
|
2020-08-03 20:01:22 +00:00
|
|
|
return false;
|
2020-05-22 16:18:23 +00:00
|
|
|
|
2020-08-03 20:01:22 +00:00
|
|
|
return true;
|
2020-05-22 16:18:23 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 00:38:25 +00:00
|
|
|
void __folio_lock(struct folio *folio);
|
2020-12-08 05:07:31 +00:00
|
|
|
int __folio_lock_killable(struct folio *folio);
|
2023-06-30 21:19:55 +00:00
|
|
|
vm_fault_t __folio_lock_or_retry(struct folio *folio, struct vm_fault *vmf);
|
2020-12-07 20:44:35 +00:00
|
|
|
void unlock_page(struct page *page);
|
|
|
|
void folio_unlock(struct folio *folio);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2022-04-04 17:24:36 +00:00
|
|
|
/**
|
|
|
|
* folio_trylock() - Attempt to lock a folio.
|
|
|
|
* @folio: The folio to attempt to lock.
|
|
|
|
*
|
|
|
|
* Sometimes it is undesirable to wait for a folio to be unlocked (eg
|
|
|
|
* when the locks are being taken in the wrong order, or if making
|
|
|
|
* progress through a batch of folios is more important than processing
|
|
|
|
* them in order). Usually folio_lock() is the correct function to call.
|
|
|
|
*
|
|
|
|
* Context: Any context.
|
|
|
|
* Return: Whether the lock was successfully acquired.
|
|
|
|
*/
|
2021-03-02 00:38:25 +00:00
|
|
|
static inline bool folio_trylock(struct folio *folio)
|
|
|
|
{
|
|
|
|
return likely(!test_and_set_bit_lock(PG_locked, folio_flags(folio, 0)));
|
|
|
|
}
|
|
|
|
|
2019-07-12 03:54:59 +00:00
|
|
|
/*
|
|
|
|
* Return true if the page was successfully locked
|
|
|
|
*/
|
2024-04-28 01:47:11 +00:00
|
|
|
static inline bool trylock_page(struct page *page)
|
2008-08-02 10:01:03 +00:00
|
|
|
{
|
2021-03-02 00:38:25 +00:00
|
|
|
return folio_trylock(page_folio(page));
|
|
|
|
}
|
|
|
|
|
2022-04-04 17:24:36 +00:00
|
|
|
/**
|
|
|
|
* folio_lock() - Lock this folio.
|
|
|
|
* @folio: The folio to lock.
|
|
|
|
*
|
|
|
|
* The folio lock protects against many things, probably more than it
|
|
|
|
* should. It is primarily held while a folio is being brought uptodate,
|
|
|
|
* either from its backing file or from swap. It is also held while a
|
|
|
|
* folio is being truncated from its address_space, so holding the lock
|
|
|
|
* is sufficient to keep folio->mapping stable.
|
|
|
|
*
|
|
|
|
* The folio lock is also held while write() is modifying the page to
|
|
|
|
* provide POSIX atomicity guarantees (as long as the write does not
|
|
|
|
* cross a page boundary). Other modifications to the data in the folio
|
|
|
|
* do not hold the folio lock and can race with writes, eg DMA and stores
|
|
|
|
* to mapped pages.
|
|
|
|
*
|
|
|
|
* Context: May sleep. If you need to acquire the locks of two or
|
|
|
|
* more folios, they must be in order of ascending index, if they are
|
|
|
|
* in the same address_space. If they are in different address_spaces,
|
|
|
|
* acquire the lock of the folio which belongs to the address_space which
|
|
|
|
* has the lowest address in memory first.
|
|
|
|
*/
|
2021-03-02 00:38:25 +00:00
|
|
|
static inline void folio_lock(struct folio *folio)
|
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
if (!folio_trylock(folio))
|
|
|
|
__folio_lock(folio);
|
2008-08-02 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
2022-04-04 17:24:36 +00:00
|
|
|
/**
|
|
|
|
* lock_page() - Lock the folio containing this page.
|
|
|
|
* @page: The page to lock.
|
|
|
|
*
|
|
|
|
* See folio_lock() for a description of what the lock protects.
|
|
|
|
* This is a legacy function and new code should probably use folio_lock()
|
|
|
|
* instead.
|
|
|
|
*
|
|
|
|
* Context: May sleep. Pages in the same folio share a lock, so do not
|
|
|
|
* attempt to lock two pages which share a folio.
|
2006-09-26 06:31:24 +00:00
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
static inline void lock_page(struct page *page)
|
|
|
|
{
|
2021-03-02 00:38:25 +00:00
|
|
|
struct folio *folio;
|
2005-04-16 22:20:36 +00:00
|
|
|
might_sleep();
|
2021-03-02 00:38:25 +00:00
|
|
|
|
|
|
|
folio = page_folio(page);
|
|
|
|
if (!folio_trylock(folio))
|
|
|
|
__folio_lock(folio);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-09-26 06:31:24 +00:00
|
|
|
|
2022-04-04 17:24:36 +00:00
|
|
|
/**
|
|
|
|
* folio_lock_killable() - Lock this folio, interruptible by a fatal signal.
|
|
|
|
* @folio: The folio to lock.
|
|
|
|
*
|
|
|
|
* Attempts to lock the folio, like folio_lock(), except that the sleep
|
|
|
|
* to acquire the lock is interruptible by a fatal signal.
|
|
|
|
*
|
|
|
|
* Context: May sleep; see folio_lock().
|
|
|
|
* Return: 0 if the lock was acquired; -EINTR if a fatal signal was received.
|
|
|
|
*/
|
2020-12-08 05:07:31 +00:00
|
|
|
static inline int folio_lock_killable(struct folio *folio)
|
|
|
|
{
|
|
|
|
might_sleep();
|
|
|
|
if (!folio_trylock(folio))
|
|
|
|
return __folio_lock_killable(folio);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-26 21:21:57 +00:00
|
|
|
/*
|
2022-09-02 19:46:53 +00:00
|
|
|
* folio_lock_or_retry - Lock the folio, unless this would block and the
|
2010-10-26 21:21:57 +00:00
|
|
|
* caller indicated that it can handle a retry.
|
2014-08-06 23:07:24 +00:00
|
|
|
*
|
2020-06-09 04:33:54 +00:00
|
|
|
* Return value and mmap_lock implications depend on flags; see
|
2021-03-19 01:39:45 +00:00
|
|
|
* __folio_lock_or_retry().
|
2010-10-26 21:21:57 +00:00
|
|
|
*/
|
2023-06-30 21:19:55 +00:00
|
|
|
static inline vm_fault_t folio_lock_or_retry(struct folio *folio,
|
|
|
|
struct vm_fault *vmf)
|
2010-10-26 21:21:57 +00:00
|
|
|
{
|
|
|
|
might_sleep();
|
2023-06-30 21:19:55 +00:00
|
|
|
if (!folio_trylock(folio))
|
|
|
|
return __folio_lock_or_retry(folio, vmf);
|
|
|
|
return 0;
|
2010-10-26 21:21:57 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2021-03-04 17:02:54 +00:00
|
|
|
* This is exported only for folio_wait_locked/folio_wait_writeback, etc.,
|
2017-02-22 23:44:41 +00:00
|
|
|
* and should not be used directly.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2021-03-04 17:02:54 +00:00
|
|
|
void folio_wait_bit(struct folio *folio, int bit_nr);
|
|
|
|
int folio_wait_bit_killable(struct folio *folio, int bit_nr);
|
2014-09-24 01:28:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2021-03-04 15:21:02 +00:00
|
|
|
* Wait for a folio to be unlocked.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2021-03-04 15:21:02 +00:00
|
|
|
* This must be called with the caller "holding" the folio,
|
2022-04-04 17:24:36 +00:00
|
|
|
* ie with increased folio reference count so that the folio won't
|
|
|
|
* go away during the wait.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2021-03-04 15:21:02 +00:00
|
|
|
static inline void folio_wait_locked(struct folio *folio)
|
|
|
|
{
|
|
|
|
if (folio_test_locked(folio))
|
2021-03-04 17:02:54 +00:00
|
|
|
folio_wait_bit(folio, PG_locked);
|
2021-03-04 15:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int folio_wait_locked_killable(struct folio *folio)
|
|
|
|
{
|
|
|
|
if (!folio_test_locked(folio))
|
|
|
|
return 0;
|
2021-03-04 17:02:54 +00:00
|
|
|
return folio_wait_bit_killable(folio, PG_locked);
|
2021-03-04 15:21:02 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static inline void wait_on_page_locked(struct page *page)
|
|
|
|
{
|
2021-03-04 15:21:02 +00:00
|
|
|
folio_wait_locked(page_folio(page));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-10-04 16:53:03 +00:00
|
|
|
void folio_end_read(struct folio *folio, bool success);
|
2019-05-14 00:23:11 +00:00
|
|
|
void wait_on_page_writeback(struct page *page);
|
2021-03-04 16:09:17 +00:00
|
|
|
void folio_wait_writeback(struct folio *folio);
|
|
|
|
int folio_wait_writeback_killable(struct folio *folio);
|
2021-03-03 20:21:55 +00:00
|
|
|
void end_page_writeback(struct page *page);
|
|
|
|
void folio_end_writeback(struct folio *folio);
|
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 00:42:51 +00:00
|
|
|
void wait_for_stable_page(struct page *page);
|
2021-03-04 16:25:25 +00:00
|
|
|
void folio_wait_stable(struct folio *folio);
|
2021-05-04 15:01:10 +00:00
|
|
|
void __folio_mark_dirty(struct folio *folio, struct address_space *, int warn);
|
2022-03-25 01:13:59 +00:00
|
|
|
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);
|
2021-03-08 21:43:04 +00:00
|
|
|
void __folio_cancel_dirty(struct folio *folio);
|
|
|
|
static inline void folio_cancel_dirty(struct folio *folio)
|
|
|
|
{
|
|
|
|
/* Avoid atomic ops, locking, etc. when not actually needed. */
|
|
|
|
if (folio_test_dirty(folio))
|
|
|
|
__folio_cancel_dirty(folio);
|
|
|
|
}
|
2021-02-28 21:21:20 +00:00
|
|
|
bool folio_clear_dirty_for_io(struct folio *folio);
|
|
|
|
bool clear_page_dirty_for_io(struct page *page);
|
2022-02-09 20:21:28 +00:00
|
|
|
void folio_invalidate(struct folio *folio, size_t offset, size_t length);
|
2022-02-09 20:22:13 +00:00
|
|
|
bool noop_dirty_folio(struct address_space *mapping, struct folio *folio);
|
2021-06-29 02:36:30 +00:00
|
|
|
|
2022-06-06 16:55:08 +00:00
|
|
|
#ifdef CONFIG_MIGRATION
|
|
|
|
int filemap_migrate_folio(struct address_space *mapping, struct folio *dst,
|
|
|
|
struct folio *src, enum migrate_mode mode);
|
|
|
|
#else
|
|
|
|
#define filemap_migrate_folio NULL
|
|
|
|
#endif
|
2021-04-23 02:58:32 +00:00
|
|
|
void folio_end_private_2(struct folio *folio);
|
|
|
|
void folio_wait_private_2(struct folio *folio);
|
|
|
|
int folio_wait_private_2_killable(struct folio *folio);
|
2020-02-10 10:00:21 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2021-08-02 11:44:20 +00:00
|
|
|
* Fault in userspace address range.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2021-08-02 11:44:20 +00:00
|
|
|
size_t fault_in_writeable(char __user *uaddr, size_t size);
|
2022-04-23 10:07:49 +00:00
|
|
|
size_t fault_in_subpage_writeable(char __user *uaddr, size_t size);
|
2021-07-05 15:26:28 +00:00
|
|
|
size_t fault_in_safe_writeable(const char __user *uaddr, size_t size);
|
2021-08-02 11:44:20 +00:00
|
|
|
size_t fault_in_readable(const char __user *uaddr, size_t size);
|
2012-03-25 17:47:41 +00:00
|
|
|
|
2008-08-02 10:01:03 +00:00
|
|
|
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
|
2020-12-08 13:56:28 +00:00
|
|
|
pgoff_t index, gfp_t gfp);
|
|
|
|
int filemap_add_folio(struct address_space *mapping, struct folio *folio,
|
|
|
|
pgoff_t index, gfp_t gfp);
|
2021-05-09 13:33:42 +00:00
|
|
|
void filemap_remove_folio(struct folio *folio);
|
|
|
|
void __filemap_remove_folio(struct folio *folio, void *shadow);
|
2022-11-01 17:53:22 +00:00
|
|
|
void replace_page_cache_folio(struct folio *old, struct folio *new);
|
2017-11-16 01:37:33 +00:00
|
|
|
void delete_from_page_cache_batch(struct address_space *mapping,
|
2021-12-07 19:15:07 +00:00
|
|
|
struct folio_batch *fbatch);
|
2021-07-28 19:14:48 +00:00
|
|
|
bool filemap_release_folio(struct folio *folio, gfp_t gfp);
|
2021-02-26 01:15:48 +00:00
|
|
|
loff_t mapping_seek_hole_data(struct address_space *, loff_t start, loff_t end,
|
|
|
|
int whence);
|
2008-08-02 10:01:03 +00:00
|
|
|
|
2020-12-08 13:56:28 +00:00
|
|
|
/* Must be non-static for BPF error injection */
|
|
|
|
int __filemap_add_folio(struct address_space *mapping, struct folio *folio,
|
|
|
|
pgoff_t index, gfp_t gfp, void **shadowp);
|
|
|
|
|
2021-10-28 14:47:05 +00:00
|
|
|
bool filemap_range_has_writeback(struct address_space *mapping,
|
|
|
|
loff_t start_byte, loff_t end_byte);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_range_needs_writeback - check if range potentially needs writeback
|
|
|
|
* @mapping: address space within which to check
|
|
|
|
* @start_byte: offset in bytes where the range starts
|
|
|
|
* @end_byte: offset in bytes where the range ends (inclusive)
|
|
|
|
*
|
|
|
|
* Find at least one page in the range supplied, usually used to check if
|
|
|
|
* direct writing in this range will trigger a writeback. Used by O_DIRECT
|
|
|
|
* read/write with IOCB_NOWAIT, to see if the caller needs to do
|
|
|
|
* filemap_write_and_wait_range() before proceeding.
|
|
|
|
*
|
|
|
|
* Return: %true if the caller should do filemap_write_and_wait_range() before
|
|
|
|
* doing O_DIRECT to a page in this range, %false otherwise.
|
|
|
|
*/
|
|
|
|
static inline bool filemap_range_needs_writeback(struct address_space *mapping,
|
|
|
|
loff_t start_byte,
|
|
|
|
loff_t end_byte)
|
|
|
|
{
|
|
|
|
if (!mapping->nrpages)
|
|
|
|
return false;
|
|
|
|
if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) &&
|
|
|
|
!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK))
|
|
|
|
return false;
|
|
|
|
return filemap_range_has_writeback(mapping, start_byte, end_byte);
|
|
|
|
}
|
|
|
|
|
2020-06-02 04:46:21 +00:00
|
|
|
/**
|
|
|
|
* struct readahead_control - Describes a readahead request.
|
|
|
|
*
|
|
|
|
* A readahead request is for consecutive pages. Filesystems which
|
|
|
|
* implement the ->readahead method should call readahead_page() or
|
|
|
|
* readahead_page_batch() in a loop and attempt to start I/O against
|
|
|
|
* each page in the request.
|
|
|
|
*
|
|
|
|
* Most of the fields in this struct are private and should be accessed
|
|
|
|
* by the functions below.
|
|
|
|
*
|
|
|
|
* @file: The file, used primarily by network filesystems for authentication.
|
|
|
|
* May be NULL if invoked internally by the filesystem.
|
|
|
|
* @mapping: Readahead this filesystem object.
|
2021-04-07 20:18:55 +00:00
|
|
|
* @ra: File readahead state. May be NULL.
|
2020-06-02 04:46:21 +00:00
|
|
|
*/
|
|
|
|
struct readahead_control {
|
|
|
|
struct file *file;
|
|
|
|
struct address_space *mapping;
|
2021-04-07 20:18:55 +00:00
|
|
|
struct file_ra_state *ra;
|
2020-06-02 04:46:21 +00:00
|
|
|
/* private: use the readahead_* accessors instead */
|
|
|
|
pgoff_t _index;
|
|
|
|
unsigned int _nr_pages;
|
|
|
|
unsigned int _batch_count;
|
2022-09-15 09:41:56 +00:00
|
|
|
bool _workingset;
|
|
|
|
unsigned long _pflags;
|
2020-06-02 04:46:21 +00:00
|
|
|
};
|
|
|
|
|
2021-04-07 20:18:55 +00:00
|
|
|
#define DEFINE_READAHEAD(ractl, f, r, m, i) \
|
|
|
|
struct readahead_control ractl = { \
|
2020-10-16 03:06:10 +00:00
|
|
|
.file = f, \
|
|
|
|
.mapping = m, \
|
2021-04-07 20:18:55 +00:00
|
|
|
.ra = r, \
|
2020-10-16 03:06:10 +00:00
|
|
|
._index = i, \
|
|
|
|
}
|
|
|
|
|
2020-10-16 03:06:28 +00:00
|
|
|
#define VM_READAHEAD_PAGES (SZ_128K / PAGE_SIZE)
|
|
|
|
|
|
|
|
void page_cache_ra_unbounded(struct readahead_control *,
|
|
|
|
unsigned long nr_to_read, unsigned long lookahead_count);
|
2021-04-07 20:18:55 +00:00
|
|
|
void page_cache_sync_ra(struct readahead_control *, unsigned long req_count);
|
2021-05-27 16:30:54 +00:00
|
|
|
void page_cache_async_ra(struct readahead_control *, struct folio *,
|
2020-10-16 03:06:28 +00:00
|
|
|
unsigned long req_count);
|
2020-09-10 13:03:27 +00:00
|
|
|
void readahead_expand(struct readahead_control *ractl,
|
|
|
|
loff_t new_start, size_t new_len);
|
2020-10-16 03:06:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* page_cache_sync_readahead - generic file readahead
|
|
|
|
* @mapping: address_space which holds the pagecache and I/O vectors
|
|
|
|
* @ra: file_ra_state which holds the readahead state
|
|
|
|
* @file: Used by the filesystem for authentication.
|
|
|
|
* @index: Index of first page to be read.
|
|
|
|
* @req_count: Total number of pages being read by the caller.
|
|
|
|
*
|
|
|
|
* page_cache_sync_readahead() should be called when a cache miss happened:
|
|
|
|
* it will submit the read. The readahead logic may decide to piggyback more
|
|
|
|
* pages onto the read request if access patterns suggest it will improve
|
|
|
|
* performance.
|
|
|
|
*/
|
|
|
|
static inline
|
|
|
|
void page_cache_sync_readahead(struct address_space *mapping,
|
|
|
|
struct file_ra_state *ra, struct file *file, pgoff_t index,
|
|
|
|
unsigned long req_count)
|
|
|
|
{
|
2021-04-07 20:18:55 +00:00
|
|
|
DEFINE_READAHEAD(ractl, file, ra, mapping, index);
|
|
|
|
page_cache_sync_ra(&ractl, req_count);
|
2020-10-16 03:06:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* page_cache_async_readahead - file readahead for marked pages
|
|
|
|
* @mapping: address_space which holds the pagecache and I/O vectors
|
|
|
|
* @ra: file_ra_state which holds the readahead state
|
|
|
|
* @file: Used by the filesystem for authentication.
|
2024-06-25 10:18:55 +00:00
|
|
|
* @folio: The folio which triggered the readahead call.
|
2020-10-16 03:06:28 +00:00
|
|
|
* @req_count: Total number of pages being read by the caller.
|
|
|
|
*
|
|
|
|
* page_cache_async_readahead() should be called when a page is used which
|
|
|
|
* is marked as PageReadahead; this is a marker to suggest that the application
|
|
|
|
* has used up enough of the readahead window that we should start pulling in
|
|
|
|
* more pages.
|
|
|
|
*/
|
|
|
|
static inline
|
|
|
|
void page_cache_async_readahead(struct address_space *mapping,
|
|
|
|
struct file_ra_state *ra, struct file *file,
|
2024-06-25 10:18:55 +00:00
|
|
|
struct folio *folio, unsigned long req_count)
|
2020-10-16 03:06:28 +00:00
|
|
|
{
|
2024-06-25 10:18:55 +00:00
|
|
|
DEFINE_READAHEAD(ractl, file, ra, mapping, folio->index);
|
2021-03-18 02:38:26 +00:00
|
|
|
page_cache_async_ra(&ractl, folio, req_count);
|
2020-10-16 03:06:28 +00:00
|
|
|
}
|
|
|
|
|
2021-04-27 20:37:09 +00:00
|
|
|
static inline struct folio *__readahead_folio(struct readahead_control *ractl)
|
|
|
|
{
|
|
|
|
struct folio *folio;
|
|
|
|
|
|
|
|
BUG_ON(ractl->_batch_count > ractl->_nr_pages);
|
|
|
|
ractl->_nr_pages -= ractl->_batch_count;
|
|
|
|
ractl->_index += ractl->_batch_count;
|
|
|
|
|
|
|
|
if (!ractl->_nr_pages) {
|
|
|
|
ractl->_batch_count = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
folio = xa_load(&ractl->mapping->i_pages, ractl->_index);
|
|
|
|
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
|
|
|
|
ractl->_batch_count = folio_nr_pages(folio);
|
|
|
|
|
|
|
|
return folio;
|
|
|
|
}
|
|
|
|
|
2020-06-02 04:46:21 +00:00
|
|
|
/**
|
|
|
|
* readahead_page - Get the next page to read.
|
2021-04-27 20:37:09 +00:00
|
|
|
* @ractl: The current readahead request.
|
2020-06-02 04:46:21 +00:00
|
|
|
*
|
|
|
|
* Context: The page is locked and has an elevated refcount. The caller
|
|
|
|
* should decreases the refcount once the page has been submitted for I/O
|
|
|
|
* and unlock the page once all I/O to that page has completed.
|
|
|
|
* Return: A pointer to the next page, or %NULL if we are done.
|
|
|
|
*/
|
2021-04-27 20:37:09 +00:00
|
|
|
static inline struct page *readahead_page(struct readahead_control *ractl)
|
2020-06-02 04:46:21 +00:00
|
|
|
{
|
2021-04-27 20:37:09 +00:00
|
|
|
struct folio *folio = __readahead_folio(ractl);
|
2020-06-02 04:46:21 +00:00
|
|
|
|
2021-04-27 20:37:09 +00:00
|
|
|
return &folio->page;
|
|
|
|
}
|
2020-06-02 04:46:21 +00:00
|
|
|
|
2021-04-27 20:37:09 +00:00
|
|
|
/**
|
|
|
|
* readahead_folio - Get the next folio to read.
|
|
|
|
* @ractl: The current readahead request.
|
|
|
|
*
|
|
|
|
* Context: The folio is locked. The caller should unlock the folio once
|
|
|
|
* all I/O to that folio has completed.
|
|
|
|
* Return: A pointer to the next folio, or %NULL if we are done.
|
|
|
|
*/
|
|
|
|
static inline struct folio *readahead_folio(struct readahead_control *ractl)
|
|
|
|
{
|
|
|
|
struct folio *folio = __readahead_folio(ractl);
|
2020-06-02 04:46:21 +00:00
|
|
|
|
2021-04-27 20:37:09 +00:00
|
|
|
if (folio)
|
|
|
|
folio_put(folio);
|
|
|
|
return folio;
|
2020-06-02 04:46:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int __readahead_batch(struct readahead_control *rac,
|
|
|
|
struct page **array, unsigned int array_sz)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
XA_STATE(xas, &rac->mapping->i_pages, 0);
|
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
BUG_ON(rac->_batch_count > rac->_nr_pages);
|
|
|
|
rac->_nr_pages -= rac->_batch_count;
|
|
|
|
rac->_index += rac->_batch_count;
|
|
|
|
rac->_batch_count = 0;
|
|
|
|
|
|
|
|
xas_set(&xas, rac->_index);
|
|
|
|
rcu_read_lock();
|
|
|
|
xas_for_each(&xas, page, rac->_index + rac->_nr_pages - 1) {
|
2020-11-22 06:17:08 +00:00
|
|
|
if (xas_retry(&xas, page))
|
|
|
|
continue;
|
2020-06-02 04:46:21 +00:00
|
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
|
|
VM_BUG_ON_PAGE(PageTail(page), page);
|
|
|
|
array[i++] = page;
|
2020-08-15 00:30:37 +00:00
|
|
|
rac->_batch_count += thp_nr_pages(page);
|
2020-06-02 04:46:21 +00:00
|
|
|
if (i == array_sz)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* readahead_page_batch - Get a batch of pages to read.
|
|
|
|
* @rac: The current readahead request.
|
|
|
|
* @array: An array of pointers to struct page.
|
|
|
|
*
|
|
|
|
* Context: The pages are locked and have an elevated refcount. The caller
|
|
|
|
* should decreases the refcount once the page has been submitted for I/O
|
|
|
|
* and unlock the page once all I/O to that page has completed.
|
|
|
|
* Return: The number of pages placed in the array. 0 indicates the request
|
|
|
|
* is complete.
|
|
|
|
*/
|
|
|
|
#define readahead_page_batch(rac, array) \
|
|
|
|
__readahead_batch(rac, array, ARRAY_SIZE(array))
|
|
|
|
|
|
|
|
/**
|
|
|
|
* readahead_pos - The byte offset into the file of this readahead request.
|
|
|
|
* @rac: The readahead request.
|
|
|
|
*/
|
|
|
|
static inline loff_t readahead_pos(struct readahead_control *rac)
|
|
|
|
{
|
|
|
|
return (loff_t)rac->_index * PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* readahead_length - The number of bytes in this readahead request.
|
|
|
|
* @rac: The readahead request.
|
|
|
|
*/
|
2021-05-15 00:27:30 +00:00
|
|
|
static inline size_t readahead_length(struct readahead_control *rac)
|
2020-06-02 04:46:21 +00:00
|
|
|
{
|
2021-05-15 00:27:30 +00:00
|
|
|
return rac->_nr_pages * PAGE_SIZE;
|
2020-06-02 04:46:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* readahead_index - The index of the first page in this readahead request.
|
|
|
|
* @rac: The readahead request.
|
|
|
|
*/
|
|
|
|
static inline pgoff_t readahead_index(struct readahead_control *rac)
|
|
|
|
{
|
|
|
|
return rac->_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* readahead_count - The number of pages in this readahead request.
|
|
|
|
* @rac: The readahead request.
|
|
|
|
*/
|
|
|
|
static inline unsigned int readahead_count(struct readahead_control *rac)
|
|
|
|
{
|
|
|
|
return rac->_nr_pages;
|
|
|
|
}
|
|
|
|
|
2021-03-21 21:03:11 +00:00
|
|
|
/**
|
|
|
|
* readahead_batch_length - The number of bytes in the current batch.
|
|
|
|
* @rac: The readahead request.
|
|
|
|
*/
|
2021-05-15 00:27:30 +00:00
|
|
|
static inline size_t readahead_batch_length(struct readahead_control *rac)
|
2021-03-21 21:03:11 +00:00
|
|
|
{
|
|
|
|
return rac->_batch_count * PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2015-05-24 15:19:41 +00:00
|
|
|
static inline unsigned long dir_pages(struct inode *inode)
|
|
|
|
{
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 12:29:47 +00:00
|
|
|
return (unsigned long)(inode->i_size + PAGE_SIZE - 1) >>
|
|
|
|
PAGE_SHIFT;
|
2015-05-24 15:19:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-29 02:30:06 +00:00
|
|
|
/**
|
|
|
|
* folio_mkwrite_check_truncate - check if folio was truncated
|
|
|
|
* @folio: the folio to check
|
|
|
|
* @inode: the inode to check the folio against
|
|
|
|
*
|
|
|
|
* Return: the number of bytes in the folio up to EOF,
|
|
|
|
* or -EFAULT if the folio was truncated.
|
|
|
|
*/
|
|
|
|
static inline ssize_t folio_mkwrite_check_truncate(struct folio *folio,
|
|
|
|
struct inode *inode)
|
|
|
|
{
|
|
|
|
loff_t size = i_size_read(inode);
|
|
|
|
pgoff_t index = size >> PAGE_SHIFT;
|
|
|
|
size_t offset = offset_in_folio(folio, size);
|
|
|
|
|
|
|
|
if (!folio->mapping)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* folio is wholly inside EOF */
|
|
|
|
if (folio_next_index(folio) - 1 < index)
|
|
|
|
return folio_size(folio);
|
|
|
|
/* folio is wholly past EOF */
|
|
|
|
if (folio->index > index || !offset)
|
|
|
|
return -EFAULT;
|
|
|
|
/* folio is partially inside EOF */
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2020-01-06 16:58:23 +00:00
|
|
|
/**
|
|
|
|
* page_mkwrite_check_truncate - check if page was truncated
|
|
|
|
* @page: the page to check
|
|
|
|
* @inode: the inode to check the page against
|
|
|
|
*
|
|
|
|
* Returns the number of bytes in the page up to EOF,
|
|
|
|
* or -EFAULT if the page was truncated.
|
|
|
|
*/
|
|
|
|
static inline int page_mkwrite_check_truncate(struct page *page,
|
|
|
|
struct inode *inode)
|
|
|
|
{
|
|
|
|
loff_t size = i_size_read(inode);
|
|
|
|
pgoff_t index = size >> PAGE_SHIFT;
|
|
|
|
int offset = offset_in_page(size);
|
|
|
|
|
|
|
|
if (page->mapping != inode->i_mapping)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* page is wholly inside EOF */
|
|
|
|
if (page->index < index)
|
|
|
|
return PAGE_SIZE;
|
|
|
|
/* page is wholly past EOF */
|
|
|
|
if (page->index > index || !offset)
|
|
|
|
return -EFAULT;
|
|
|
|
/* page is partially inside EOF */
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2020-09-21 15:58:39 +00:00
|
|
|
/**
|
2021-04-28 03:11:28 +00:00
|
|
|
* i_blocks_per_folio - How many blocks fit in this folio.
|
2020-09-21 15:58:39 +00:00
|
|
|
* @inode: The inode which contains the blocks.
|
2021-04-28 03:11:28 +00:00
|
|
|
* @folio: The folio.
|
2020-09-21 15:58:39 +00:00
|
|
|
*
|
2021-04-28 03:11:28 +00:00
|
|
|
* If the block size is larger than the size of this folio, return zero.
|
2020-09-21 15:58:39 +00:00
|
|
|
*
|
2021-04-28 03:11:28 +00:00
|
|
|
* Context: The caller should hold a refcount on the folio to prevent it
|
2020-09-21 15:58:39 +00:00
|
|
|
* from being split.
|
2021-04-28 03:11:28 +00:00
|
|
|
* Return: The number of filesystem blocks covered by this folio.
|
2020-09-21 15:58:39 +00:00
|
|
|
*/
|
2021-04-28 03:11:28 +00:00
|
|
|
static inline
|
|
|
|
unsigned int i_blocks_per_folio(struct inode *inode, struct folio *folio)
|
|
|
|
{
|
|
|
|
return folio_size(folio) >> inode->i_blkbits;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif /* _LINUX_PAGEMAP_H */
|