Blame view

mm/fadvise.c 3.71 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * mm/fadvise.c
   *
   * Copyright (C) 2002, Linus Torvalds
   *
e1f8e8744   Francois Cami   Remove Andrew Mor...
6
   * 11Jan2003	Andrew Morton
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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>
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
18
  #include <linux/writeback.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/syscalls.h>
67d46b296   Mel Gorman   mm/fadvise.c: dra...
20
  #include <linux/swap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
  
  #include <asm/unistd.h>
  
  /*
   * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
   * deactivate the pages and clear PG_Referenced.
   */
4a0fd5bf0   Al Viro   teach SYSCALL_DEF...
28
  SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  {
2903ff019   Al Viro   switch simple cas...
30
  	struct fd f = fdget(fd);
e748dcd09   Matthew Wilcox   vfs: remove get_x...
31
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  	struct address_space *mapping;
  	struct backing_dev_info *bdi;
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
34
  	loff_t endbyte;			/* inclusive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
  	pgoff_t start_index;
  	pgoff_t end_index;
  	unsigned long nrpages;
  	int ret = 0;
2903ff019   Al Viro   switch simple cas...
39
  	if (!f.file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  		return -EBADF;
e748dcd09   Matthew Wilcox   vfs: remove get_x...
41
42
  	inode = file_inode(f.file);
  	if (S_ISFIFO(inode->i_mode)) {
87ba81dba   Valentine Barshak   [PATCH] fadvise: ...
43
44
45
  		ret = -ESPIPE;
  		goto out;
  	}
2903ff019   Al Viro   switch simple cas...
46
  	mapping = f.file->f_mapping;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  	if (!mapping || len < 0) {
  		ret = -EINVAL;
  		goto out;
  	}
e748dcd09   Matthew Wilcox   vfs: remove get_x...
51
  	if (IS_DAX(inode)) {
b5beb1caf   Masatake YAMATO   check ADVICE of f...
52
53
54
55
56
57
58
59
60
61
62
63
  		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;
  		}
fe77ba6f4   Carsten Otte   [PATCH] xip: madv...
64
  		goto out;
b5beb1caf   Masatake YAMATO   check ADVICE of f...
65
  	}
fe77ba6f4   Carsten Otte   [PATCH] xip: madv...
66

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
  	/* Careful about overflows. Len == 0 means "as much as possible" */
  	endbyte = offset + len;
  	if (!len || endbyte < len)
  		endbyte = -1;
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
71
72
  	else
  		endbyte--;		/* inclusive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

de1414a65   Christoph Hellwig   fs: export inode_...
74
  	bdi = inode_to_bdi(mapping->host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  
  	switch (advice) {
  	case POSIX_FADV_NORMAL:
2903ff019   Al Viro   switch simple cas...
78
79
80
81
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  		break;
  	case POSIX_FADV_RANDOM:
2903ff019   Al Viro   switch simple cas...
84
85
86
  		spin_lock(&f.file->f_lock);
  		f.file->f_mode |= FMODE_RANDOM;
  		spin_unlock(&f.file->f_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
  		break;
  	case POSIX_FADV_SEQUENTIAL:
2903ff019   Al Viro   switch simple cas...
89
90
91
92
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  		break;
  	case POSIX_FADV_WILLNEED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
  		/* First and last PARTIAL page! */
  		start_index = offset >> PAGE_CACHE_SHIFT;
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
97
  		end_index = endbyte >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
  
  		/* Careful about overflow on the "+1" */
  		nrpages = end_index - start_index + 1;
  		if (!nrpages)
  			nrpages = ~0UL;
3d3727cdb   KOSAKI Motohiro   mm, fadvise: don'...
103
104
105
106
107
  
  		/*
  		 * Ignore return value because fadvise() shall return
  		 * success even if filesystem can't retrieve a hint,
  		 */
2903ff019   Al Viro   switch simple cas...
108
  		force_page_cache_readahead(mapping, f.file, start_index,
3d3727cdb   KOSAKI Motohiro   mm, fadvise: don'...
109
  					   nrpages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		break;
60c371bc7   Andrew Morton   [PATCH] fadvise()...
111
112
  	case POSIX_FADV_NOREUSE:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  	case POSIX_FADV_DONTNEED:
de1414a65   Christoph Hellwig   fs: export inode_...
114
  		if (!bdi_write_congested(bdi))
ad8a1b558   Shawn Bohrer   fadvise: only ini...
115
116
  			__filemap_fdatawrite_range(mapping, offset, endbyte,
  						   WB_SYNC_NONE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

441c228f8   Mel Gorman   mm: fadvise: docu...
118
119
120
121
122
  		/*
  		 * First and last FULL page! Partial pages are deliberately
  		 * preserved on the expectation that it is better to preserve
  		 * needed memory than to discard unneeded memory.
  		 */
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
123
  		start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  		end_index = (endbyte >> PAGE_CACHE_SHIFT);
67d46b296   Mel Gorman   mm/fadvise.c: dra...
125
126
127
128
129
130
131
132
133
134
135
136
137
  		if (end_index >= start_index) {
  			unsigned long count = invalidate_mapping_pages(mapping,
  						start_index, end_index);
  
  			/*
  			 * If fewer pages were invalidated than expected then
  			 * it is possible that some of the pages were on
  			 * a per-cpu pagevec for a remote CPU. Drain all
  			 * pagevecs and try again.
  			 */
  			if (count < (end_index - start_index + 1)) {
  				lru_add_drain_all();
  				invalidate_mapping_pages(mapping, start_index,
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
138
  						end_index);
67d46b296   Mel Gorman   mm/fadvise.c: dra...
139
140
  			}
  		}
ebcf28e1c   Andrew Morton   [PATCH] fadvise()...
141
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
  	default:
  		ret = -EINVAL;
  	}
  out:
2903ff019   Al Viro   switch simple cas...
146
  	fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
  	return ret;
  }
  
  #ifdef __ARCH_WANT_SYS_FADVISE64
4a0fd5bf0   Al Viro   teach SYSCALL_DEF...
151
  SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
  {
  	return sys_fadvise64_64(fd, offset, len, advice);
  }
  
  #endif