Blame view

mm/fadvise.c 5.27 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   * mm/fadvise.c
   *
   * Copyright (C) 2002, Linus Torvalds
   *
e1f8e8744   Francois Cami   Remove Andrew Mor...
7
   * 11Jan2003	Andrew Morton
1da177e4c   Linus Torvalds   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   Andrew Morton   [PATCH] fadvise()...
19
  #include <linux/writeback.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/syscalls.h>
67d46b296   Mel Gorman   mm/fadvise.c: dra...
21
  #include <linux/swap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  
  #include <asm/unistd.h>
cee9a0c4e   Matthew Wilcox (Oracle)   mm: move readahea...
24
  #include "internal.h"
1da177e4c   Linus Torvalds   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   Dominik Brodowski   mm: add ksys_fadv...
29

cf1ea0592   Jan Kara   fs: Export generi...
30
  int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  {
e748dcd09   Matthew Wilcox   vfs: remove get_x...
32
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  	struct address_space *mapping;
  	struct backing_dev_info *bdi;
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
35
  	loff_t endbyte;			/* inclusive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
  	pgoff_t start_index;
  	pgoff_t end_index;
  	unsigned long nrpages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

45cd0faae   Amir Goldstein   vfs: add the fadv...
40
41
42
  	inode = file_inode(file);
  	if (S_ISFIFO(inode->i_mode))
  		return -ESPIPE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

45cd0faae   Amir Goldstein   vfs: add the fadv...
44
45
46
  	mapping = file->f_mapping;
  	if (!mapping || len < 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

3a77d2148   Shakeel Butt   mm: fadvise: avoi...
48
49
50
  	bdi = inode_to_bdi(mapping->host);
  
  	if (IS_DAX(inode) || (bdi == &noop_backing_dev_info)) {
b5beb1caf   Masatake YAMATO   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   Amir Goldstein   vfs: add the fadv...
61
  			return -EINVAL;
b5beb1caf   Masatake YAMATO   check ADVICE of f...
62
  		}
45cd0faae   Amir Goldstein   vfs: add the fadv...
63
  		return 0;
b5beb1caf   Masatake YAMATO   check ADVICE of f...
64
  	}
fe77ba6f4   Carsten Otte   [PATCH] xip: madv...
65

a718e28f5   Andrey Ryabinin   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   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	if (!len || endbyte < len)
  		endbyte = -1;
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
74
75
  	else
  		endbyte--;		/* inclusive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  	switch (advice) {
  	case POSIX_FADV_NORMAL:
45cd0faae   Amir Goldstein   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   Linus Torvalds   Linux-2.6.12-rc2
83
84
  		break;
  	case POSIX_FADV_RANDOM:
45cd0faae   Amir Goldstein   vfs: add the fadv...
85
86
87
  		spin_lock(&file->f_lock);
  		file->f_mode |= FMODE_RANDOM;
  		spin_unlock(&file->f_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  		break;
  	case POSIX_FADV_SEQUENTIAL:
45cd0faae   Amir Goldstein   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   Linus Torvalds   Linux-2.6.12-rc2
94
95
  		break;
  	case POSIX_FADV_WILLNEED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  		/* First and last PARTIAL page! */
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
97
98
  		start_index = offset >> PAGE_SHIFT;
  		end_index = endbyte >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   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   KOSAKI Motohiro   mm, fadvise: don'...
104

45cd0faae   Amir Goldstein   vfs: add the fadv...
105
  		force_page_cache_readahead(mapping, file, start_index, nrpages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  		break;
60c371bc7   Andrew Morton   [PATCH] fadvise()...
107
108
  	case POSIX_FADV_NOREUSE:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  	case POSIX_FADV_DONTNEED:
703c27088   Tejun Heo   writeback: implem...
110
  		if (!inode_write_congested(mapping->host))
ad8a1b558   Shawn Bohrer   fadvise: only ini...
111
112
  			__filemap_fdatawrite_range(mapping, offset, endbyte,
  						   WB_SYNC_NONE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

441c228f8   Mel Gorman   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   Kirill A. Shutemov   mm, fs: get rid o...
119
120
  		start_index = (offset+(PAGE_SIZE-1)) >> PAGE_SHIFT;
  		end_index = (endbyte >> PAGE_SHIFT);
a7ab400d6   shidao.ytt   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   Oleg Drokin   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   Linus Torvalds   Linux-2.6.12-rc2
140

67d46b296   Mel Gorman   mm/fadvise.c: dra...
141
  		if (end_index >= start_index) {
eb1d7a65f   Yafang Shao   mm, fadvise: impr...
142
  			unsigned long nr_pagevec = 0;
4dd72b4a4   Johannes Weiner   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   Yafang Shao   mm, fadvise: impr...
154
155
156
  			invalidate_mapping_pagevec(mapping,
  						start_index, end_index,
  						&nr_pagevec);
67d46b296   Mel Gorman   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   Yafang Shao   mm, fadvise: impr...
164
  			if (nr_pagevec) {
67d46b296   Mel Gorman   mm/fadvise.c: dra...
165
166
  				lru_add_drain_all();
  				invalidate_mapping_pages(mapping, start_index,
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
167
  						end_index);
67d46b296   Mel Gorman   mm/fadvise.c: dra...
168
169
  			}
  		}
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
170
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	default:
45cd0faae   Amir Goldstein   vfs: add the fadv...
172
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	}
45cd0faae   Amir Goldstein   vfs: add the fadv...
174
175
  	return 0;
  }
cf1ea0592   Jan Kara   fs: Export generi...
176
  EXPORT_SYMBOL(generic_fadvise);
45cd0faae   Amir Goldstein   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   Amir Goldstein   vfs: implement re...
186
  #ifdef CONFIG_ADVISE_SYSCALLS
45cd0faae   Amir Goldstein   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   Al Viro   switch simple cas...
196
  	fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
  	return ret;
  }
9d5b7c956   Dominik Brodowski   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   Linus Torvalds   Linux-2.6.12-rc2
203
  #ifdef __ARCH_WANT_SYS_FADVISE64
4a0fd5bf0   Al Viro   teach SYSCALL_DEF...
204
  SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  {
9d5b7c956   Dominik Brodowski   mm: add ksys_fadv...
206
  	return ksys_fadvise64_64(fd, offset, len, advice);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
  }
  
  #endif
3d8f76153   Amir Goldstein   vfs: implement re...
210
  #endif