fadvise.c 3.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * mm/fadvise.c
 *
 * Copyright (C) 2002, Linus Torvalds
 *
6
 * 11Jan2003	Andrew Morton
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16 17
 *		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>
18
#include <linux/writeback.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26
#include <linux/syscalls.h>

#include <asm/unistd.h>

/*
 * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
 * deactivate the pages and clear PG_Referenced.
 */
27
SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
L
Linus Torvalds 已提交
28
{
29
	struct fd f = fdget(fd);
L
Linus Torvalds 已提交
30 31
	struct address_space *mapping;
	struct backing_dev_info *bdi;
32
	loff_t endbyte;			/* inclusive */
L
Linus Torvalds 已提交
33 34 35 36 37
	pgoff_t start_index;
	pgoff_t end_index;
	unsigned long nrpages;
	int ret = 0;

38
	if (!f.file)
L
Linus Torvalds 已提交
39 40
		return -EBADF;

41
	if (S_ISFIFO(f.file->f_path.dentry->d_inode->i_mode)) {
42 43 44 45
		ret = -ESPIPE;
		goto out;
	}

46
	mapping = f.file->f_mapping;
L
Linus Torvalds 已提交
47 48 49 50 51
	if (!mapping || len < 0) {
		ret = -EINVAL;
		goto out;
	}

52
	if (mapping->a_ops->get_xip_mem) {
53 54 55 56 57 58 59 60 61 62 63 64
		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:
			ret = -EINVAL;
		}
65
		goto out;
66
	}
67

L
Linus Torvalds 已提交
68 69 70 71
	/* Careful about overflows. Len == 0 means "as much as possible" */
	endbyte = offset + len;
	if (!len || endbyte < len)
		endbyte = -1;
72 73
	else
		endbyte--;		/* inclusive */
L
Linus Torvalds 已提交
74 75 76 77 78

	bdi = mapping->backing_dev_info;

	switch (advice) {
	case POSIX_FADV_NORMAL:
79 80 81 82
		f.file->f_ra.ra_pages = bdi->ra_pages;
		spin_lock(&f.file->f_lock);
		f.file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
L
Linus Torvalds 已提交
83 84
		break;
	case POSIX_FADV_RANDOM:
85 86 87
		spin_lock(&f.file->f_lock);
		f.file->f_mode |= FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
L
Linus Torvalds 已提交
88 89
		break;
	case POSIX_FADV_SEQUENTIAL:
90 91 92 93
		f.file->f_ra.ra_pages = bdi->ra_pages * 2;
		spin_lock(&f.file->f_lock);
		f.file->f_mode &= ~FMODE_RANDOM;
		spin_unlock(&f.file->f_lock);
L
Linus Torvalds 已提交
94 95 96 97
		break;
	case POSIX_FADV_WILLNEED:
		/* First and last PARTIAL page! */
		start_index = offset >> PAGE_CACHE_SHIFT;
98
		end_index = endbyte >> PAGE_CACHE_SHIFT;
L
Linus Torvalds 已提交
99 100 101 102 103

		/* Careful about overflow on the "+1" */
		nrpages = end_index - start_index + 1;
		if (!nrpages)
			nrpages = ~0UL;
104 105 106 107 108

		/*
		 * Ignore return value because fadvise() shall return
		 * success even if filesystem can't retrieve a hint,
		 */
109
		force_page_cache_readahead(mapping, f.file, start_index,
110
					   nrpages);
L
Linus Torvalds 已提交
111
		break;
112 113
	case POSIX_FADV_NOREUSE:
		break;
L
Linus Torvalds 已提交
114 115
	case POSIX_FADV_DONTNEED:
		if (!bdi_write_congested(mapping->backing_dev_info))
116 117
			__filemap_fdatawrite_range(mapping, offset, endbyte,
						   WB_SYNC_NONE);
L
Linus Torvalds 已提交
118 119

		/* First and last FULL page! */
120
		start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
L
Linus Torvalds 已提交
121 122
		end_index = (endbyte >> PAGE_CACHE_SHIFT);

123 124 125 126
		if (end_index >= start_index)
			invalidate_mapping_pages(mapping, start_index,
						end_index);
		break;
L
Linus Torvalds 已提交
127 128 129 130
	default:
		ret = -EINVAL;
	}
out:
131
	fdput(f);
L
Linus Torvalds 已提交
132 133
	return ret;
}
134 135 136 137 138 139 140
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice)
{
	return SYSC_fadvise64_64((int) fd, offset, len, (int) advice);
}
SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64);
#endif
L
Linus Torvalds 已提交
141 142 143

#ifdef __ARCH_WANT_SYS_FADVISE64

144
SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice)
L
Linus Torvalds 已提交
145 146 147
{
	return sys_fadvise64_64(fd, offset, len, advice);
}
148 149 150 151 152 153 154
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice)
{
	return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice);
}
SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64);
#endif
L
Linus Torvalds 已提交
155 156

#endif