Root/mm/fadvise.c

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 */
28SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
29{
30    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    if (!f.file)
40        return -EBADF;
41
42    if (S_ISFIFO(file_inode(f.file)->i_mode)) {
43        ret = -ESPIPE;
44        goto out;
45    }
46
47    mapping = f.file->f_mapping;
48    if (!mapping || len < 0) {
49        ret = -EINVAL;
50        goto out;
51    }
52
53    if (mapping->a_ops->get_xip_mem) {
54        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    endbyte = offset + len;
71    if (!len || endbyte < len)
72        endbyte = -1;
73    else
74        endbyte--; /* inclusive */
75
76    bdi = mapping->backing_dev_info;
77
78    switch (advice) {
79    case POSIX_FADV_NORMAL:
80        f.file->f_ra.ra_pages = bdi->ra_pages;
81        spin_lock(&f.file->f_lock);
82        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        f.file->f_mode |= FMODE_RANDOM;
88        spin_unlock(&f.file->f_lock);
89        break;
90    case POSIX_FADV_SEQUENTIAL:
91        f.file->f_ra.ra_pages = bdi->ra_pages * 2;
92        spin_lock(&f.file->f_lock);
93        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        start_index = offset >> PAGE_CACHE_SHIFT;
99        end_index = endbyte >> PAGE_CACHE_SHIFT;
100
101        /* Careful about overflow on the "+1" */
102        nrpages = end_index - start_index + 1;
103        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        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        if (!bdi_write_congested(mapping->backing_dev_info))
117            __filemap_fdatawrite_range(mapping, offset, endbyte,
118                           WB_SYNC_NONE);
119
120        /* First and last FULL page! */
121        start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
122        end_index = (endbyte >> PAGE_CACHE_SHIFT);
123
124        if (end_index >= start_index) {
125            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            if (count < (end_index - start_index + 1)) {
135                lru_add_drain_all();
136                invalidate_mapping_pages(mapping, start_index,
137                        end_index);
138            }
139        }
140        break;
141    default:
142        ret = -EINVAL;
143    }
144out:
145    fdput(f);
146    return ret;
147}
148
149#ifdef __ARCH_WANT_SYS_FADVISE64
150
151SYSCALL_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
157

Archive Download this file



interactive