Branch data Line data Source code
1 : : /*
2 : : * mm/fadvise.c
3 : : *
4 : : * Copyright (C) 2002, Linus Torvalds
5 : : *
6 : : * 11Jan2003 Andrew Morton
7 : : * Initial version.
8 : : */
9 : :
10 : : #include <linux/kernel.h>
11 : : #include <linux/file.h>
12 : : #include <linux/fs.h>
13 : : #include <linux/mm.h>
14 : : #include <linux/pagemap.h>
15 : : #include <linux/backing-dev.h>
16 : : #include <linux/pagevec.h>
17 : : #include <linux/fadvise.h>
18 : : #include <linux/writeback.h>
19 : : #include <linux/syscalls.h>
20 : : #include <linux/swap.h>
21 : :
22 : : #include <asm/unistd.h>
23 : :
24 : : /*
25 : : * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
26 : : * deactivate the pages and clear PG_Referenced.
27 : : */
28 : 0 : SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
29 : : {
30 : 1096 : struct fd f = fdget(fd);
31 : : struct address_space *mapping;
32 : : struct backing_dev_info *bdi;
33 : : loff_t endbyte; /* inclusive */
34 : : pgoff_t start_index;
35 : : pgoff_t end_index;
36 : : unsigned long nrpages;
37 : : int ret = 0;
38 : :
39 [ + + ]: 1096 : if (!f.file)
40 : : return -EBADF;
41 : :
42 [ + + ]: 1084 : if (S_ISFIFO(file_inode(f.file)->i_mode)) {
43 : : ret = -ESPIPE;
44 : : goto out;
45 : : }
46 : :
47 : 588 : mapping = f.file->f_mapping;
48 [ + - ]: 588 : if (!mapping || len < 0) {
49 : : ret = -EINVAL;
50 : : goto out;
51 : : }
52 : :
53 [ - + ]: 588 : if (mapping->a_ops->get_xip_mem) {
54 [ # # ]: 0 : switch (advice) {
55 : : case POSIX_FADV_NORMAL:
56 : : case POSIX_FADV_RANDOM:
57 : : case POSIX_FADV_SEQUENTIAL:
58 : : case POSIX_FADV_WILLNEED:
59 : : case POSIX_FADV_NOREUSE:
60 : : case POSIX_FADV_DONTNEED:
61 : : /* no bad return value, but ignore advice */
62 : : break;
63 : : default:
64 : : ret = -EINVAL;
65 : : }
66 : : goto out;
67 : : }
68 : :
69 : : /* Careful about overflows. Len == 0 means "as much as possible" */
70 : 588 : endbyte = offset + len;
71 [ - + ]: 588 : if (!len || endbyte < len)
72 : : endbyte = -1;
73 : : else
74 : 0 : endbyte--; /* inclusive */
75 : :
76 : 588 : bdi = mapping->backing_dev_info;
77 : :
78 [ + + + + : 588 : switch (advice) {
+ + + ]
79 : : case POSIX_FADV_NORMAL:
80 : 2 : f.file->f_ra.ra_pages = bdi->ra_pages;
81 : : spin_lock(&f.file->f_lock);
82 : 2 : f.file->f_mode &= ~FMODE_RANDOM;
83 : : spin_unlock(&f.file->f_lock);
84 : : break;
85 : : case POSIX_FADV_RANDOM:
86 : : spin_lock(&f.file->f_lock);
87 : 156 : f.file->f_mode |= FMODE_RANDOM;
88 : : spin_unlock(&f.file->f_lock);
89 : : break;
90 : : case POSIX_FADV_SEQUENTIAL:
91 : 372 : f.file->f_ra.ra_pages = bdi->ra_pages * 2;
92 : : spin_lock(&f.file->f_lock);
93 : 372 : f.file->f_mode &= ~FMODE_RANDOM;
94 : : spin_unlock(&f.file->f_lock);
95 : : break;
96 : : case POSIX_FADV_WILLNEED:
97 : : /* First and last PARTIAL page! */
98 : 2 : start_index = offset >> PAGE_CACHE_SHIFT;
99 : 2 : end_index = endbyte >> PAGE_CACHE_SHIFT;
100 : :
101 : : /* Careful about overflow on the "+1" */
102 : 2 : nrpages = end_index - start_index + 1;
103 [ + - ]: 2 : if (!nrpages)
104 : : nrpages = ~0UL;
105 : :
106 : : /*
107 : : * Ignore return value because fadvise() shall return
108 : : * success even if filesystem can't retrieve a hint,
109 : : */
110 : 2 : force_page_cache_readahead(mapping, f.file, start_index,
111 : : nrpages);
112 : : break;
113 : : case POSIX_FADV_NOREUSE:
114 : : break;
115 : : case POSIX_FADV_DONTNEED:
116 [ + - ]: 1098 : if (!bdi_write_congested(mapping->backing_dev_info))
117 : 2 : __filemap_fdatawrite_range(mapping, offset, endbyte,
118 : : WB_SYNC_NONE);
119 : :
120 : : /* First and last FULL page! */
121 : 2 : start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
122 : 2 : end_index = (endbyte >> PAGE_CACHE_SHIFT);
123 : :
124 [ + - ]: 2 : if (end_index >= start_index) {
125 : 2 : unsigned long count = invalidate_mapping_pages(mapping,
126 : : start_index, end_index);
127 : :
128 : : /*
129 : : * If fewer pages were invalidated than expected then
130 : : * it is possible that some of the pages were on
131 : : * a per-cpu pagevec for a remote CPU. Drain all
132 : : * pagevecs and try again.
133 : : */
134 [ - + ]: 2 : if (count < (end_index - start_index + 1)) {
135 : 0 : lru_add_drain_all();
136 : 52 : invalidate_mapping_pages(mapping, start_index,
137 : : end_index);
138 : : }
139 : : }
140 : : break;
141 : : default:
142 : : ret = -EINVAL;
143 : : }
144 : : out:
145 : : fdput(f);
146 : : return ret;
147 : : }
148 : :
149 : : #ifdef __ARCH_WANT_SYS_FADVISE64
150 : :
151 : : SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
152 : : {
153 : : return sys_fadvise64_64(fd, offset, len, advice);
154 : : }
155 : :
156 : : #endif
|