Blame view
mm/fadvise.c
5.27 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 |
/* * mm/fadvise.c * * Copyright (C) 2002, Linus Torvalds * |
e1f8e8744 Remove Andrew Mor... |
7 |
* 11Jan2003 Andrew Morton |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 15 16 17 18 |
* 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> |
ebcf28e1c [PATCH] fadvise()... |
19 |
#include <linux/writeback.h> |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include <linux/syscalls.h> |
67d46b296 mm/fadvise.c: dra... |
21 |
#include <linux/swap.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 |
#include <asm/unistd.h> |
cee9a0c4e mm: move readahea... |
24 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
25 26 27 28 |
/* * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could * deactivate the pages and clear PG_Referenced. */ |
9d5b7c956 mm: add ksys_fadv... |
29 |
|
cf1ea0592 fs: Export generi... |
30 |
int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) |
1da177e4c Linux-2.6.12-rc2 |
31 |
{ |
e748dcd09 vfs: remove get_x... |
32 |
struct inode *inode; |
1da177e4c Linux-2.6.12-rc2 |
33 34 |
struct address_space *mapping; struct backing_dev_info *bdi; |
ebcf28e1c [PATCH] fadvise()... |
35 |
loff_t endbyte; /* inclusive */ |
1da177e4c Linux-2.6.12-rc2 |
36 37 38 |
pgoff_t start_index; pgoff_t end_index; unsigned long nrpages; |
1da177e4c Linux-2.6.12-rc2 |
39 |
|
45cd0faae vfs: add the fadv... |
40 41 42 |
inode = file_inode(file); if (S_ISFIFO(inode->i_mode)) return -ESPIPE; |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
45cd0faae vfs: add the fadv... |
44 45 46 |
mapping = file->f_mapping; if (!mapping || len < 0) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
3a77d2148 mm: fadvise: avoi... |
48 49 50 |
bdi = inode_to_bdi(mapping->host); if (IS_DAX(inode) || (bdi == &noop_backing_dev_info)) { |
b5beb1caf check ADVICE of f... |
51 52 53 54 55 56 57 58 59 60 |
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: |
45cd0faae vfs: add the fadv... |
61 |
return -EINVAL; |
b5beb1caf check ADVICE of f... |
62 |
} |
45cd0faae vfs: add the fadv... |
63 |
return 0; |
b5beb1caf check ADVICE of f... |
64 |
} |
fe77ba6f4 [PATCH] xip: madv... |
65 |
|
a718e28f5 mm/fadvise.c: fix... |
66 67 68 69 70 71 |
/* * Careful about overflows. Len == 0 means "as much as possible". Use * unsigned math because signed overflows are undefined and UBSan * complains. */ endbyte = (u64)offset + (u64)len; |
1da177e4c Linux-2.6.12-rc2 |
72 73 |
if (!len || endbyte < len) endbyte = -1; |
ebcf28e1c [PATCH] fadvise()... |
74 75 |
else endbyte--; /* inclusive */ |
1da177e4c Linux-2.6.12-rc2 |
76 |
|
1da177e4c Linux-2.6.12-rc2 |
77 78 |
switch (advice) { case POSIX_FADV_NORMAL: |
45cd0faae vfs: add the fadv... |
79 80 81 82 |
file->f_ra.ra_pages = bdi->ra_pages; spin_lock(&file->f_lock); file->f_mode &= ~FMODE_RANDOM; spin_unlock(&file->f_lock); |
1da177e4c Linux-2.6.12-rc2 |
83 84 |
break; case POSIX_FADV_RANDOM: |
45cd0faae vfs: add the fadv... |
85 86 87 |
spin_lock(&file->f_lock); file->f_mode |= FMODE_RANDOM; spin_unlock(&file->f_lock); |
1da177e4c Linux-2.6.12-rc2 |
88 89 |
break; case POSIX_FADV_SEQUENTIAL: |
45cd0faae vfs: add the fadv... |
90 91 92 93 |
file->f_ra.ra_pages = bdi->ra_pages * 2; spin_lock(&file->f_lock); file->f_mode &= ~FMODE_RANDOM; spin_unlock(&file->f_lock); |
1da177e4c Linux-2.6.12-rc2 |
94 95 |
break; case POSIX_FADV_WILLNEED: |
1da177e4c Linux-2.6.12-rc2 |
96 |
/* First and last PARTIAL page! */ |
09cbfeaf1 mm, fs: get rid o... |
97 98 |
start_index = offset >> PAGE_SHIFT; end_index = endbyte >> PAGE_SHIFT; |
1da177e4c Linux-2.6.12-rc2 |
99 100 101 102 103 |
/* Careful about overflow on the "+1" */ nrpages = end_index - start_index + 1; if (!nrpages) nrpages = ~0UL; |
3d3727cdb mm, fadvise: don'... |
104 |
|
45cd0faae vfs: add the fadv... |
105 |
force_page_cache_readahead(mapping, file, start_index, nrpages); |
1da177e4c Linux-2.6.12-rc2 |
106 |
break; |
60c371bc7 [PATCH] fadvise()... |
107 108 |
case POSIX_FADV_NOREUSE: break; |
1da177e4c Linux-2.6.12-rc2 |
109 |
case POSIX_FADV_DONTNEED: |
703c27088 writeback: implem... |
110 |
if (!inode_write_congested(mapping->host)) |
ad8a1b558 fadvise: only ini... |
111 112 |
__filemap_fdatawrite_range(mapping, offset, endbyte, WB_SYNC_NONE); |
1da177e4c Linux-2.6.12-rc2 |
113 |
|
441c228f8 mm: fadvise: docu... |
114 115 116 117 118 |
/* * 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. */ |
09cbfeaf1 mm, fs: get rid o... |
119 120 |
start_index = (offset+(PAGE_SIZE-1)) >> PAGE_SHIFT; end_index = (endbyte >> PAGE_SHIFT); |
a7ab400d6 mm/fadvise: disca... |
121 122 123 124 125 126 127 128 129 |
/* * 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) { |
18aba41cb mm/fadvise.c: do ... |
130 131 132 133 134 135 136 137 138 139 |
/* 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--; } |
1da177e4c Linux-2.6.12-rc2 |
140 |
|
67d46b296 mm/fadvise.c: dra... |
141 |
if (end_index >= start_index) { |
eb1d7a65f mm, fadvise: impr... |
142 |
unsigned long nr_pagevec = 0; |
4dd72b4a4 mm: fadvise: avoi... |
143 144 145 146 147 148 149 150 151 152 153 |
/* * 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(); |
eb1d7a65f mm, fadvise: impr... |
154 155 156 |
invalidate_mapping_pagevec(mapping, start_index, end_index, &nr_pagevec); |
67d46b296 mm/fadvise.c: dra... |
157 158 159 160 161 162 163 |
/* * 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. */ |
eb1d7a65f mm, fadvise: impr... |
164 |
if (nr_pagevec) { |
67d46b296 mm/fadvise.c: dra... |
165 166 |
lru_add_drain_all(); invalidate_mapping_pages(mapping, start_index, |
ebcf28e1c [PATCH] fadvise()... |
167 |
end_index); |
67d46b296 mm/fadvise.c: dra... |
168 169 |
} } |
ebcf28e1c [PATCH] fadvise()... |
170 |
break; |
1da177e4c Linux-2.6.12-rc2 |
171 |
default: |
45cd0faae vfs: add the fadv... |
172 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
173 |
} |
45cd0faae vfs: add the fadv... |
174 175 |
return 0; } |
cf1ea0592 fs: Export generi... |
176 |
EXPORT_SYMBOL(generic_fadvise); |
45cd0faae vfs: add the fadv... |
177 178 179 180 181 182 183 184 185 |
int vfs_fadvise(struct file *file, loff_t offset, loff_t len, int advice) { if (file->f_op->fadvise) return file->f_op->fadvise(file, offset, len, advice); return generic_fadvise(file, offset, len, advice); } EXPORT_SYMBOL(vfs_fadvise); |
3d8f76153 vfs: implement re... |
186 |
#ifdef CONFIG_ADVISE_SYSCALLS |
45cd0faae vfs: add the fadv... |
187 188 189 190 191 192 193 194 195 |
int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) { struct fd f = fdget(fd); int ret; if (!f.file) return -EBADF; ret = vfs_fadvise(f.file, offset, len, advice); |
2903ff019 switch simple cas... |
196 |
fdput(f); |
1da177e4c Linux-2.6.12-rc2 |
197 198 |
return ret; } |
9d5b7c956 mm: add ksys_fadv... |
199 200 201 202 |
SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) { return ksys_fadvise64_64(fd, offset, len, advice); } |
1da177e4c Linux-2.6.12-rc2 |
203 |
#ifdef __ARCH_WANT_SYS_FADVISE64 |
4a0fd5bf0 teach SYSCALL_DEF... |
204 |
SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice) |
1da177e4c Linux-2.6.12-rc2 |
205 |
{ |
9d5b7c956 mm: add ksys_fadv... |
206 |
return ksys_fadvise64_64(fd, offset, len, advice); |
1da177e4c Linux-2.6.12-rc2 |
207 208 209 |
} #endif |
3d8f76153 vfs: implement re... |
210 |
#endif |