linux/mm/fadvise.c
<<
>>
Prefs
   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_DEFINE(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(f.file->f_path.dentry->d_inode->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#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
 149asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice)
 150{
 151        return SYSC_fadvise64_64((int) fd, offset, len, (int) advice);
 152}
 153SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64);
 154#endif
 155
 156#ifdef __ARCH_WANT_SYS_FADVISE64
 157
 158SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice)
 159{
 160        return sys_fadvise64_64(fd, offset, len, advice);
 161}
 162#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
 163asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice)
 164{
 165        return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice);
 166}
 167SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64);
 168#endif
 169
 170#endif
 171
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.