Release 4.18 mm/fadvise.c
// SPDX-License-Identifier: GPL-2.0
/*
* mm/fadvise.c
*
* Copyright (C) 2002, Linus Torvalds
*
* 11Jan2003 Andrew Morton
* Initial version.
*/
#include <linux/kernel.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/backing-dev.h>
#include <linux/pagevec.h>
#include <linux/fadvise.h>
#include <linux/writeback.h>
#include <linux/syscalls.h>
#include <linux/swap.h>
#include <asm/unistd.h>
/*
* POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
* deactivate the pages and clear PG_Referenced.
*/
int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
{
struct fd f = fdget(fd);
struct inode *inode;
struct address_space *mapping;
struct backing_dev_info *bdi;
loff_t endbyte; /* inclusive */
pgoff_t start_index;
pgoff_t end_index;
unsigned long nrpages;
int ret = 0;
if (!f.file)
return -EBADF;
inode = file_inode(f.file);
if (S_ISFIFO(inode->i_mode)) {
ret = -ESPIPE;
goto out;
}
mapping = f.file->f_mapping;
if (!mapping || len < 0) {
ret = -EINVAL;
goto out;
}
bdi = inode_to_bdi(mapping->host);
if (IS_DAX(inode) || (bdi == &noop_backing_dev_info)) {
switch (advice) {
case POSIX_FADV_NORMAL:
case POSIX_FADV_RANDOM:
case POSIX_FADV_SEQUENTIAL:
case POSIX_FADV_WILLNEED:
case POSIX_FADV_NOREUSE:
case POSIX_FADV_DONTNEED:
/* no bad return value, but ignore advice */
break;
default:
ret = -EINVAL;
}
goto out;
}
/* Careful about overflows. Len == 0 means "as much as possible" */
endbyte = offset + len;
if (!len || endbyte < len)
endbyte = -1;
else
endbyte--; /* inclusive */
switch (advice) {
case POSIX_FADV_NORMAL:
f.file->f_ra.ra_pages = bdi->ra_pages;
spin_lock(&f.file->f_lock);
f.file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&f.file->f_lock);
break;
case POSIX_FADV_RANDOM:
spin_lock(&f.file->f_lock);
f.file->f_mode |= FMODE_RANDOM;
spin_unlock(&f.file->f_lock);
break;
case POSIX_FADV_SEQUENTIAL:
f.file->f_ra.ra_pages = bdi->ra_pages * 2;
spin_lock(&f.file->f_lock);
f.file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&f.file->f_lock);
break;
case POSIX_FADV_WILLNEED:
/* First and last PARTIAL page! */
start_index = offset >> PAGE_SHIFT;
end_index = endbyte >> PAGE_SHIFT;
/* Careful about overflow on the "+1" */
nrpages = end_index - start_index + 1;
if (!nrpages)
nrpages = ~0UL;
/*
* Ignore return value because fadvise() shall return
* success even if filesystem can't retrieve a hint,
*/
force_page_cache_readahead(mapping, f.file, start_index,
nrpages);
break;
case POSIX_FADV_NOREUSE:
break;
case POSIX_FADV_DONTNEED:
if (!inode_write_congested(mapping->host))
__filemap_fdatawrite_range(mapping, offset, endbyte,
WB_SYNC_NONE);
/*
* First and last FULL page! Partial pages are deliberately
* preserved on the expectation that it is better to preserve
* needed memory than to discard unneeded memory.
*/
start_index = (offset+(PAGE_SIZE-1)) >> PAGE_SHIFT;
end_index = (endbyte >> PAGE_SHIFT);
/*
* The page at end_index will be inclusively discarded according
* by invalidate_mapping_pages(), so subtracting 1 from
* end_index means we will skip the last page. But if endbyte
* is page aligned or is at the end of file, we should not skip
* that page - discarding the last page is safe enough.
*/
if ((endbyte & ~PAGE_MASK) != ~PAGE_MASK &&
endbyte != inode->i_size - 1) {
/* First page is tricky as 0 - 1 = -1, but pgoff_t
* is unsigned, so the end_index >= start_index
* check below would be true and we'll discard the whole
* file cache which is not what was asked.
*/
if (end_index == 0)
break;
end_index--;
}
if (end_index >= start_index) {
unsigned long count;
/*
* It's common to FADV_DONTNEED right after
* the read or write that instantiates the
* pages, in which case there will be some
* sitting on the local LRU cache. Try to
* avoid the expensive remote drain and the
* second cache tree walk below by flushing
* them out right away.
*/
lru_add_drain();
count = invalidate_mapping_pages(mapping,
start_index, end_index);
/*
* If fewer pages were invalidated than expected then
* it is possible that some of the pages were on
* a per-cpu pagevec for a remote CPU. Drain all
* pagevecs and try again.
*/
if (count < (end_index - start_index + 1)) {
lru_add_drain_all();
invalidate_mapping_pages(mapping, start_index,
end_index);
}
}
break;
default:
ret = -EINVAL;
}
out:
fdput(f);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 191 | 34.85% | 11 | 36.67% |
Fengguang Wu | 65 | 11.86% | 1 | 3.33% |
Linus Torvalds | 60 | 10.95% | 1 | 3.33% |
Al Viro | 38 | 6.93% | 2 | 6.67% |
Masatake YAMATO | 33 | 6.02% | 1 | 3.33% |
Mel Gorman | 32 | 5.84% | 2 | 6.67% |
Oleg Drokin | 25 | 4.56% | 1 | 3.33% |
Matthew Wilcox | 17 | 3.10% | 1 | 3.33% |
Shakeel Butt | 16 | 2.92% | 1 | 3.33% |
Valentine Barshak | 15 | 2.74% | 1 | 3.33% |
Dominik Brodowski | 15 | 2.74% | 1 | 3.33% |
shidao.ytt | 9 | 1.64% | 1 | 3.33% |
Johannes Weiner | 8 | 1.46% | 1 | 3.33% |
Shawn Bohrer | 7 | 1.28% | 1 | 3.33% |
Carsten Otte | 7 | 1.28% | 1 | 3.33% |
Kirill A. Shutemov | 5 | 0.91% | 1 | 3.33% |
Tejun Heo | 4 | 0.73% | 1 | 3.33% |
Motohiro Kosaki | 1 | 0.18% | 1 | 3.33% |
Total | 548 | 100.00% | 30 | 100.00% |
SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
{
return ksys_fadvise64_64(fd, offset, len, advice);
}
#ifdef __ARCH_WANT_SYS_FADVISE64
SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
{
return ksys_fadvise64_64(fd, offset, len, advice);
}
#endif
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 230 | 34.85% | 14 | 36.84% |
Fengguang Wu | 65 | 9.85% | 1 | 2.63% |
Linus Torvalds | 60 | 9.09% | 1 | 2.63% |
Dominik Brodowski | 50 | 7.58% | 1 | 2.63% |
Al Viro | 50 | 7.58% | 3 | 7.89% |
Mel Gorman | 35 | 5.30% | 2 | 5.26% |
Masatake YAMATO | 33 | 5.00% | 1 | 2.63% |
Oleg Drokin | 25 | 3.79% | 1 | 2.63% |
Heiko Carstens | 18 | 2.73% | 1 | 2.63% |
Matthew Wilcox | 17 | 2.58% | 1 | 2.63% |
Shakeel Butt | 16 | 2.42% | 1 | 2.63% |
Valentine Barshak | 15 | 2.27% | 1 | 2.63% |
shidao.ytt | 9 | 1.36% | 1 | 2.63% |
Johannes Weiner | 8 | 1.21% | 1 | 2.63% |
Shawn Bohrer | 7 | 1.06% | 1 | 2.63% |
Carsten Otte | 7 | 1.06% | 1 | 2.63% |
Kirill A. Shutemov | 5 | 0.76% | 1 | 2.63% |
Tejun Heo | 4 | 0.61% | 1 | 2.63% |
Arnd Bergmann | 3 | 0.45% | 1 | 2.63% |
Motohiro Kosaki | 1 | 0.15% | 1 | 2.63% |
Greg Kroah-Hartman | 1 | 0.15% | 1 | 2.63% |
Francois Cami | 1 | 0.15% | 1 | 2.63% |
Total | 660 | 100.00% | 38 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.