patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / mm / fadvise.c
1 /*
2  * mm/fadvise.c
3  *
4  * Copyright (C) 2002, Linus Torvalds
5  *
6  * 11Jan2003    akpm@digeo.com
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
19 #include <asm/unistd.h>
20
21 /*
22  * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
23  * deactivate the pages and clear PG_Referenced.
24  */
25 asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
26 {
27         struct file *file = fget(fd);
28         struct address_space *mapping;
29         struct backing_dev_info *bdi;
30         loff_t endbyte;
31         pgoff_t start_index;
32         pgoff_t end_index;
33         unsigned long nrpages;
34         int ret = 0;
35
36         if (!file)
37                 return -EBADF;
38
39         mapping = file->f_mapping;
40         if (!mapping || len < 0) {
41                 ret = -EINVAL;
42                 goto out;
43         }
44
45         /* Careful about overflows. Len == 0 means "as much as possible" */
46         endbyte = offset + len;
47         if (!len || endbyte < len)
48                 endbyte = -1;
49
50         bdi = mapping->backing_dev_info;
51
52         switch (advice) {
53         case POSIX_FADV_NORMAL:
54                 file->f_ra.ra_pages = bdi->ra_pages;
55                 break;
56         case POSIX_FADV_RANDOM:
57                 file->f_ra.ra_pages = 0;
58                 break;
59         case POSIX_FADV_SEQUENTIAL:
60                 file->f_ra.ra_pages = bdi->ra_pages * 2;
61                 break;
62         case POSIX_FADV_WILLNEED:
63         case POSIX_FADV_NOREUSE:
64                 if (!mapping->a_ops->readpage) {
65                         ret = -EINVAL;
66                         break;
67                 }
68
69                 /* First and last PARTIAL page! */
70                 start_index = offset >> PAGE_CACHE_SHIFT;
71                 end_index = (endbyte-1) >> PAGE_CACHE_SHIFT;
72
73                 /* Careful about overflow on the "+1" */
74                 nrpages = end_index - start_index + 1;
75                 if (!nrpages)
76                         nrpages = ~0UL;
77                 
78                 ret = force_page_cache_readahead(mapping, file,
79                                 start_index,
80                                 max_sane_readahead(nrpages));
81                 if (ret > 0)
82                         ret = 0;
83                 break;
84         case POSIX_FADV_DONTNEED:
85                 if (!bdi_write_congested(mapping->backing_dev_info))
86                         filemap_flush(mapping);
87
88                 /* First and last FULL page! */
89                 start_index = (offset + (PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
90                 end_index = (endbyte >> PAGE_CACHE_SHIFT);
91
92                 if (end_index > start_index)
93                         invalidate_mapping_pages(mapping, start_index, end_index-1);
94                 break;
95         default:
96                 ret = -EINVAL;
97         }
98 out:
99         fput(file);
100         return ret;
101 }
102
103 #ifdef __ARCH_WANT_SYS_FADVISE64
104
105 asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice)
106 {
107         return sys_fadvise64_64(fd, offset, len, advice);
108 }
109
110 #endif