Blame view

fs/read_write.c 39.2 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  linux/fs/read_write.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
b12fb7f46   Ingo Molnar   sched/headers: Pr...
7
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/stat.h>
b12fb7f46   Ingo Molnar   sched/headers: Pr...
9
  #include <linux/sched/xacct.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
  #include <linux/fcntl.h>
  #include <linux/file.h>
  #include <linux/uio.h>
0eeca2830   Robert Love   [PATCH] inotify
13
  #include <linux/fsnotify.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/security.h>
630d9c472   Paul Gortmaker   fs: reduce the us...
15
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/syscalls.h>
e28cc7157   Linus Torvalds   Relax the rw_veri...
17
  #include <linux/pagemap.h>
d6b29d7ce   Jens Axboe   splice: divorce t...
18
  #include <linux/splice.h>
561c67319   Al Viro   switch lseek to C...
19
  #include <linux/compat.h>
29732938a   Zach Brown   vfs: add copy_fil...
20
  #include <linux/mount.h>
2feb55f89   Wouter van Kesteren   fs: allow no_seek...
21
  #include <linux/fs.h>
06ae43f34   Al Viro   Don't bother with...
22
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
24
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <asm/unistd.h>
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
26
  const struct file_operations generic_ro_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  	.llseek		= generic_file_llseek,
aad4f8bb4   Al Viro   switch simple gen...
28
  	.read_iter	= generic_file_read_iter,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  	.mmap		= generic_file_readonly_mmap,
534f2aaa6   Jens Axboe   sys_sendfile: swi...
30
  	.splice_read	= generic_file_splice_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  };
  
  EXPORT_SYMBOL(generic_ro_fops);
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
34
  static inline bool unsigned_offsets(struct file *file)
4a3956c79   KAMEZAWA Hiroyuki   vfs: introduce FM...
35
  {
cccb5a1e6   Al Viro   fix signedness me...
36
  	return file->f_mode & FMODE_UNSIGNED_OFFSET;
4a3956c79   KAMEZAWA Hiroyuki   vfs: introduce FM...
37
  }
46a1c2c7a   Jie Liu   vfs: export lseek...
38
39
40
41
42
43
44
45
46
47
48
49
50
  /**
   * vfs_setpos - update the file offset for lseek
   * @file:	file structure in question
   * @offset:	file offset to seek to
   * @maxsize:	maximum file size
   *
   * This is a low-level filesystem helper for updating the file offset to
   * the value specified by @offset if the given offset is valid and it is
   * not equal to the current file offset.
   *
   * Return the specified offset on success and -EINVAL on invalid offset.
   */
  loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
51
52
53
54
55
56
57
58
59
60
61
62
  {
  	if (offset < 0 && !unsigned_offsets(file))
  		return -EINVAL;
  	if (offset > maxsize)
  		return -EINVAL;
  
  	if (offset != file->f_pos) {
  		file->f_pos = offset;
  		file->f_version = 0;
  	}
  	return offset;
  }
46a1c2c7a   Jie Liu   vfs: export lseek...
63
  EXPORT_SYMBOL(vfs_setpos);
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
64

3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
65
  /**
5760495a8   Andi Kleen   vfs: add generic_...
66
   * generic_file_llseek_size - generic llseek implementation for regular files
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
67
68
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
965c8e59c   Andrew Morton   lseek: the "whenc...
69
   * @whence:	type of seek
e8b96eb50   Eric Sandeen   vfs: allow custom...
70
71
   * @size:	max size of this file in file system
   * @eof:	offset used for SEEK_END position
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
72
   *
5760495a8   Andi Kleen   vfs: add generic_...
73
   * This is a variant of generic_file_llseek that allows passing in a custom
e8b96eb50   Eric Sandeen   vfs: allow custom...
74
   * maximum file size and a custom EOF position, for e.g. hashed directories
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
75
76
   *
   * Synchronization:
5760495a8   Andi Kleen   vfs: add generic_...
77
   * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
78
79
   * SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes.
   * read/writes behave like SEEK_SET against seeks.
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
80
   */
9465efc9e   Andi Kleen   Remove BKL from r...
81
  loff_t
965c8e59c   Andrew Morton   lseek: the "whenc...
82
  generic_file_llseek_size(struct file *file, loff_t offset, int whence,
e8b96eb50   Eric Sandeen   vfs: allow custom...
83
  		loff_t maxsize, loff_t eof)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
965c8e59c   Andrew Morton   lseek: the "whenc...
85
  	switch (whence) {
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
86
  	case SEEK_END:
e8b96eb50   Eric Sandeen   vfs: allow custom...
87
  		offset += eof;
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
88
89
  		break;
  	case SEEK_CUR:
5b6f1eb97   Alain Knaff   vfs: lseek(fd, 0,...
90
91
92
93
94
95
96
97
  		/*
  		 * Here we special-case the lseek(fd, 0, SEEK_CUR)
  		 * position-querying operation.  Avoid rewriting the "same"
  		 * f_pos value back to the file because a concurrent read(),
  		 * write() or lseek() might have altered it
  		 */
  		if (offset == 0)
  			return file->f_pos;
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
98
99
100
101
102
103
  		/*
  		 * f_lock protects against read/modify/write race with other
  		 * SEEK_CURs. Note that parallel writes and reads behave
  		 * like SEEK_SET.
  		 */
  		spin_lock(&file->f_lock);
46a1c2c7a   Jie Liu   vfs: export lseek...
104
  		offset = vfs_setpos(file, file->f_pos + offset, maxsize);
ef3d0fd27   Andi Kleen   vfs: do (nearly) ...
105
106
  		spin_unlock(&file->f_lock);
  		return offset;
982d81658   Josef Bacik   fs: add SEEK_HOLE...
107
108
109
110
111
  	case SEEK_DATA:
  		/*
  		 * In the generic case the entire file is data, so as long as
  		 * offset isn't at the end of the file then the offset is data.
  		 */
fc46820b2   Andreas Gruenbacher   vfs: Return -ENXI...
112
  		if ((unsigned long long)offset >= eof)
982d81658   Josef Bacik   fs: add SEEK_HOLE...
113
114
115
116
117
118
119
  			return -ENXIO;
  		break;
  	case SEEK_HOLE:
  		/*
  		 * There is a virtual hole at the end of the file, so as long as
  		 * offset isn't i_size or larger, return i_size.
  		 */
fc46820b2   Andreas Gruenbacher   vfs: Return -ENXI...
120
  		if ((unsigned long long)offset >= eof)
982d81658   Josef Bacik   fs: add SEEK_HOLE...
121
  			return -ENXIO;
e8b96eb50   Eric Sandeen   vfs: allow custom...
122
  		offset = eof;
982d81658   Josef Bacik   fs: add SEEK_HOLE...
123
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	}
3a8cff4f0   Christoph Hellwig   [PATCH] generic_f...
125

46a1c2c7a   Jie Liu   vfs: export lseek...
126
  	return vfs_setpos(file, offset, maxsize);
5760495a8   Andi Kleen   vfs: add generic_...
127
128
129
130
131
132
133
  }
  EXPORT_SYMBOL(generic_file_llseek_size);
  
  /**
   * generic_file_llseek - generic llseek implementation for regular files
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
965c8e59c   Andrew Morton   lseek: the "whenc...
134
   * @whence:	type of seek
5760495a8   Andi Kleen   vfs: add generic_...
135
136
137
   *
   * This is a generic implemenation of ->llseek useable for all normal local
   * filesystems.  It just updates the file offset to the value specified by
546ae2d2f   Ming Lei   fs/read_write.c: ...
138
   * @offset and @whence.
5760495a8   Andi Kleen   vfs: add generic_...
139
   */
965c8e59c   Andrew Morton   lseek: the "whenc...
140
  loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
5760495a8   Andi Kleen   vfs: add generic_...
141
142
  {
  	struct inode *inode = file->f_mapping->host;
965c8e59c   Andrew Morton   lseek: the "whenc...
143
  	return generic_file_llseek_size(file, offset, whence,
e8b96eb50   Eric Sandeen   vfs: allow custom...
144
145
  					inode->i_sb->s_maxbytes,
  					i_size_read(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  }
9465efc9e   Andi Kleen   Remove BKL from r...
147
  EXPORT_SYMBOL(generic_file_llseek);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

ae6afc3f5   jan Blunck   vfs: introduce no...
149
  /**
1bf9d14df   Al Viro   new helper: fixed...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
   * fixed_size_llseek - llseek implementation for fixed-sized devices
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
   * @whence:	type of seek
   * @size:	size of the file
   *
   */
  loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
  {
  	switch (whence) {
  	case SEEK_SET: case SEEK_CUR: case SEEK_END:
  		return generic_file_llseek_size(file, offset, whence,
  						size, size);
  	default:
  		return -EINVAL;
  	}
  }
  EXPORT_SYMBOL(fixed_size_llseek);
  
  /**
b25472f9b   Al Viro   new helpers: no_s...
170
171
172
173
174
175
176
177
178
179
180
   * no_seek_end_llseek - llseek implementation for fixed-sized devices
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
   * @whence:	type of seek
   *
   */
  loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
  {
  	switch (whence) {
  	case SEEK_SET: case SEEK_CUR:
  		return generic_file_llseek_size(file, offset, whence,
2feb55f89   Wouter van Kesteren   fs: allow no_seek...
181
  						OFFSET_MAX, 0);
b25472f9b   Al Viro   new helpers: no_s...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	default:
  		return -EINVAL;
  	}
  }
  EXPORT_SYMBOL(no_seek_end_llseek);
  
  /**
   * no_seek_end_llseek_size - llseek implementation for fixed-sized devices
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
   * @whence:	type of seek
   * @size:	maximal offset allowed
   *
   */
  loff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size)
  {
  	switch (whence) {
  	case SEEK_SET: case SEEK_CUR:
  		return generic_file_llseek_size(file, offset, whence,
  						size, 0);
  	default:
  		return -EINVAL;
  	}
  }
  EXPORT_SYMBOL(no_seek_end_llseek_size);
  
  /**
ae6afc3f5   jan Blunck   vfs: introduce no...
209
210
211
   * noop_llseek - No Operation Performed llseek implementation
   * @file:	file structure to seek on
   * @offset:	file offset to seek to
965c8e59c   Andrew Morton   lseek: the "whenc...
212
   * @whence:	type of seek
ae6afc3f5   jan Blunck   vfs: introduce no...
213
214
215
216
217
218
   *
   * This is an implementation of ->llseek useable for the rare special case when
   * userspace expects the seek to succeed but the (device) file is actually not
   * able to perform the seek. In this case you use noop_llseek() instead of
   * falling back to the default implementation of ->llseek.
   */
965c8e59c   Andrew Morton   lseek: the "whenc...
219
  loff_t noop_llseek(struct file *file, loff_t offset, int whence)
ae6afc3f5   jan Blunck   vfs: introduce no...
220
221
222
223
  {
  	return file->f_pos;
  }
  EXPORT_SYMBOL(noop_llseek);
965c8e59c   Andrew Morton   lseek: the "whenc...
224
  loff_t no_llseek(struct file *file, loff_t offset, int whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
  {
  	return -ESPIPE;
  }
  EXPORT_SYMBOL(no_llseek);
965c8e59c   Andrew Morton   lseek: the "whenc...
229
  loff_t default_llseek(struct file *file, loff_t offset, int whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  {
496ad9aa8   Al Viro   new helper: file_...
231
  	struct inode *inode = file_inode(file);
16abef0e9   David Sterba   fs: use loff_t ty...
232
  	loff_t retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233

5955102c9   Al Viro   wrappers for ->i_...
234
  	inode_lock(inode);
965c8e59c   Andrew Morton   lseek: the "whenc...
235
  	switch (whence) {
7b8e89249   Chris Snook   use symbolic cons...
236
  		case SEEK_END:
982d81658   Josef Bacik   fs: add SEEK_HOLE...
237
  			offset += i_size_read(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  			break;
7b8e89249   Chris Snook   use symbolic cons...
239
  		case SEEK_CUR:
5b6f1eb97   Alain Knaff   vfs: lseek(fd, 0,...
240
241
242
243
  			if (offset == 0) {
  				retval = file->f_pos;
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  			offset += file->f_pos;
982d81658   Josef Bacik   fs: add SEEK_HOLE...
245
246
247
248
249
250
251
  			break;
  		case SEEK_DATA:
  			/*
  			 * In the generic case the entire file is data, so as
  			 * long as offset isn't at the end of the file then the
  			 * offset is data.
  			 */
bacb2d816   Dan Carpenter   fs: add missing u...
252
253
254
255
  			if (offset >= inode->i_size) {
  				retval = -ENXIO;
  				goto out;
  			}
982d81658   Josef Bacik   fs: add SEEK_HOLE...
256
257
258
259
260
261
262
  			break;
  		case SEEK_HOLE:
  			/*
  			 * There is a virtual hole at the end of the file, so
  			 * as long as offset isn't i_size or larger, return
  			 * i_size.
  			 */
bacb2d816   Dan Carpenter   fs: add missing u...
263
264
265
266
  			if (offset >= inode->i_size) {
  				retval = -ENXIO;
  				goto out;
  			}
982d81658   Josef Bacik   fs: add SEEK_HOLE...
267
268
  			offset = inode->i_size;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
  	}
  	retval = -EINVAL;
cccb5a1e6   Al Viro   fix signedness me...
271
  	if (offset >= 0 || unsigned_offsets(file)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
  		if (offset != file->f_pos) {
  			file->f_pos = offset;
  			file->f_version = 0;
  		}
  		retval = offset;
  	}
5b6f1eb97   Alain Knaff   vfs: lseek(fd, 0,...
278
  out:
5955102c9   Al Viro   wrappers for ->i_...
279
  	inode_unlock(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
  	return retval;
  }
  EXPORT_SYMBOL(default_llseek);
965c8e59c   Andrew Morton   lseek: the "whenc...
283
  loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
  {
  	loff_t (*fn)(struct file *, loff_t, int);
  
  	fn = no_llseek;
  	if (file->f_mode & FMODE_LSEEK) {
72c2d5319   Al Viro   file->f_op is nev...
289
  		if (file->f_op->llseek)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
  			fn = file->f_op->llseek;
  	}
965c8e59c   Andrew Morton   lseek: the "whenc...
292
  	return fn(file, offset, whence);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  }
  EXPORT_SYMBOL(vfs_llseek);
bef173299   Christoph Hellwig   initrd: switch in...
295
  static off_t ksys_lseek(unsigned int fd, off_t offset, unsigned int whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
  {
  	off_t retval;
9c225f265   Linus Torvalds   vfs: atomic f_pos...
298
  	struct fd f = fdget_pos(fd);
2903ff019   Al Viro   switch simple cas...
299
300
  	if (!f.file)
  		return -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  
  	retval = -EINVAL;
965c8e59c   Andrew Morton   lseek: the "whenc...
303
304
  	if (whence <= SEEK_MAX) {
  		loff_t res = vfs_llseek(f.file, offset, whence);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
  		retval = res;
  		if (res != (loff_t)retval)
  			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
  	}
9c225f265   Linus Torvalds   vfs: atomic f_pos...
309
  	fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  	return retval;
  }
76847e434   Dominik Brodowski   fs: add ksys_lsee...
312
313
314
315
  SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
  {
  	return ksys_lseek(fd, offset, whence);
  }
561c67319   Al Viro   switch lseek to C...
316
317
318
  #ifdef CONFIG_COMPAT
  COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned int, whence)
  {
76847e434   Dominik Brodowski   fs: add ksys_lsee...
319
  	return ksys_lseek(fd, offset, whence);
561c67319   Al Viro   switch lseek to C...
320
321
  }
  #endif
9e62ccec3   Michal Suchanek   powerpc: Add back...
322
323
  #if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT) || \
  	defined(__ARCH_WANT_SYS_LLSEEK)
003d7ab47   Heiko Carstens   [CVE-2009-0029] S...
324
325
  SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
  		unsigned long, offset_low, loff_t __user *, result,
965c8e59c   Andrew Morton   lseek: the "whenc...
326
  		unsigned int, whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  {
  	int retval;
d7a15f8d0   Eric Biggers   vfs: atomic f_pos...
329
  	struct fd f = fdget_pos(fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	loff_t offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331

2903ff019   Al Viro   switch simple cas...
332
333
  	if (!f.file)
  		return -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  
  	retval = -EINVAL;
965c8e59c   Andrew Morton   lseek: the "whenc...
336
  	if (whence > SEEK_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  		goto out_putf;
2903ff019   Al Viro   switch simple cas...
338
  	offset = vfs_llseek(f.file, ((loff_t) offset_high << 32) | offset_low,
965c8e59c   Andrew Morton   lseek: the "whenc...
339
  			whence);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
  
  	retval = (int)offset;
  	if (offset >= 0) {
  		retval = -EFAULT;
  		if (!copy_to_user(result, &offset, sizeof(offset)))
  			retval = 0;
  	}
  out_putf:
d7a15f8d0   Eric Biggers   vfs: atomic f_pos...
348
  	fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
  	return retval;
  }
  #endif
68d70d03f   Al Viro   constify rw_verif...
352
  int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  {
  	struct inode *inode;
c43e259cc   James Morris   security: call se...
355
  	int retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

496ad9aa8   Al Viro   new helper: file_...
357
  	inode = file_inode(file);
e28cc7157   Linus Torvalds   Relax the rw_veri...
358
  	if (unlikely((ssize_t) count < 0))
c43e259cc   James Morris   security: call se...
359
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360

438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	/*
  	 * ranged mandatory locking does not apply to streams - it makes sense
  	 * only for files where position has a meaning.
  	 */
  	if (ppos) {
  		loff_t pos = *ppos;
  
  		if (unlikely(pos < 0)) {
  			if (!unsigned_offsets(file))
  				return retval;
  			if (count >= -pos) /* both values are in 0..LLONG_MAX */
  				return -EOVERFLOW;
  		} else if (unlikely((loff_t) (pos + count) < 0)) {
  			if (!unsigned_offsets(file))
  				return retval;
  		}
  
  		if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
  			retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
  					read_write == READ ? F_RDLCK : F_WRLCK);
  			if (retval < 0)
  				return retval;
  		}
e28cc7157   Linus Torvalds   Relax the rw_veri...
384
  	}
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
385

bc61384dc   Al Viro   rw_verify_area():...
386
  	return security_file_permission(file,
c43e259cc   James Morris   security: call se...
387
  				read_write == READ ? MAY_READ : MAY_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  }
5d5d56897   Al Viro   make new_sync_{re...
389
  static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
293bc9822   Al Viro   new methods: ->re...
390
391
392
393
394
395
396
  {
  	struct iovec iov = { .iov_base = buf, .iov_len = len };
  	struct kiocb kiocb;
  	struct iov_iter iter;
  	ssize_t ret;
  
  	init_sync_kiocb(&kiocb, filp);
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
397
  	kiocb.ki_pos = (ppos ? *ppos : 0);
293bc9822   Al Viro   new methods: ->re...
398
  	iov_iter_init(&iter, READ, &iov, 1, len);
bb7462b6f   Miklos Szeredi   vfs: use helpers ...
399
  	ret = call_read_iter(filp, &kiocb, &iter);
599bd19bd   Christoph Hellwig   fs: don't allow t...
400
  	BUG_ON(ret == -EIOCBQUEUED);
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
401
402
  	if (ppos)
  		*ppos = kiocb.ki_pos;
293bc9822   Al Viro   new methods: ->re...
403
404
  	return ret;
  }
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
405
406
407
408
409
410
411
412
  static int warn_unsupported(struct file *file, const char *op)
  {
  	pr_warn_ratelimited(
  		"kernel %s not supported for file %pD4 (pid: %d comm: %.20s)
  ",
  		op, file, current->pid, current->comm);
  	return -EINVAL;
  }
61a707c54   Christoph Hellwig   fs: add a __kerne...
413
414
  ssize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
  {
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
415
416
417
418
419
420
  	struct kvec iov = {
  		.iov_base	= buf,
  		.iov_len	= min_t(size_t, count, MAX_RW_COUNT),
  	};
  	struct kiocb kiocb;
  	struct iov_iter iter;
61a707c54   Christoph Hellwig   fs: add a __kerne...
421
422
423
424
425
426
  	ssize_t ret;
  
  	if (WARN_ON_ONCE(!(file->f_mode & FMODE_READ)))
  		return -EINVAL;
  	if (!(file->f_mode & FMODE_CAN_READ))
  		return -EINVAL;
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
427
428
429
430
431
432
  	/*
  	 * Also fail if ->read_iter and ->read are both wired up as that
  	 * implies very convoluted semantics.
  	 */
  	if (unlikely(!file->f_op->read_iter || file->f_op->read))
  		return warn_unsupported(file, "read");
61a707c54   Christoph Hellwig   fs: add a __kerne...
433

4d03e3cc5   Christoph Hellwig   fs: don't allow k...
434
  	init_sync_kiocb(&kiocb, file);
7b84b665c   Matthew Wilcox (Oracle)   fs: Allow a NULL ...
435
  	kiocb.ki_pos = pos ? *pos : 0;
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
436
437
  	iov_iter_kvec(&iter, READ, &iov, 1, iov.iov_len);
  	ret = file->f_op->read_iter(&kiocb, &iter);
61a707c54   Christoph Hellwig   fs: add a __kerne...
438
  	if (ret > 0) {
7b84b665c   Matthew Wilcox (Oracle)   fs: Allow a NULL ...
439
440
  		if (pos)
  			*pos = kiocb.ki_pos;
61a707c54   Christoph Hellwig   fs: add a __kerne...
441
442
443
444
445
446
  		fsnotify_access(file);
  		add_rchar(current, ret);
  	}
  	inc_syscr(current);
  	return ret;
  }
bdd1d2d3d   Christoph Hellwig   fs: fix kernel_re...
447
  ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
c41fbad01   Christoph Hellwig   fs: move kernel_r...
448
  {
6209dd913   Christoph Hellwig   fs: implement ker...
449
  	ssize_t ret;
c41fbad01   Christoph Hellwig   fs: move kernel_r...
450

6209dd913   Christoph Hellwig   fs: implement ker...
451
452
453
454
  	ret = rw_verify_area(READ, file, pos, count);
  	if (ret)
  		return ret;
  	return __kernel_read(file, buf, count, pos);
c41fbad01   Christoph Hellwig   fs: move kernel_r...
455
456
  }
  EXPORT_SYMBOL(kernel_read);
6fb5032eb   Dmitry Kasatkin   VFS: refactor vfs...
457

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
  ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
  {
  	ssize_t ret;
  
  	if (!(file->f_mode & FMODE_READ))
  		return -EBADF;
7f7f25e82   Al Viro   replace checking ...
464
  	if (!(file->f_mode & FMODE_CAN_READ))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  		return -EINVAL;
96d4f267e   Linus Torvalds   Remove 'type' arg...
466
  	if (unlikely(!access_ok(buf, count)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
  		return -EFAULT;
  
  	ret = rw_verify_area(READ, file, pos, count);
775802c05   Christoph Hellwig   fs: remove __vfs_...
470
471
472
473
  	if (ret)
  		return ret;
  	if (count > MAX_RW_COUNT)
  		count =  MAX_RW_COUNT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474

775802c05   Christoph Hellwig   fs: remove __vfs_...
475
476
477
478
479
480
481
482
483
484
485
  	if (file->f_op->read)
  		ret = file->f_op->read(file, buf, count, pos);
  	else if (file->f_op->read_iter)
  		ret = new_sync_read(file, buf, count, pos);
  	else
  		ret = -EINVAL;
  	if (ret > 0) {
  		fsnotify_access(file);
  		add_rchar(current, ret);
  	}
  	inc_syscr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  	return ret;
  }
5d5d56897   Al Viro   make new_sync_{re...
488
  static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
293bc9822   Al Viro   new methods: ->re...
489
490
491
492
493
494
495
  {
  	struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
  	struct kiocb kiocb;
  	struct iov_iter iter;
  	ssize_t ret;
  
  	init_sync_kiocb(&kiocb, filp);
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
496
  	kiocb.ki_pos = (ppos ? *ppos : 0);
293bc9822   Al Viro   new methods: ->re...
497
  	iov_iter_init(&iter, WRITE, &iov, 1, len);
bb7462b6f   Miklos Szeredi   vfs: use helpers ...
498
  	ret = call_write_iter(filp, &kiocb, &iter);
599bd19bd   Christoph Hellwig   fs: don't allow t...
499
  	BUG_ON(ret == -EIOCBQUEUED);
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
500
  	if (ret > 0 && ppos)
f765b134c   Al Viro   new_sync_write():...
501
  		*ppos = kiocb.ki_pos;
293bc9822   Al Viro   new methods: ->re...
502
503
  	return ret;
  }
81238b2cf   Christoph Hellwig   fs: implement ker...
504
  /* caller is responsible for file_start_write/file_end_write */
73e18f7c0   Christoph Hellwig   fs: make the buf ...
505
  ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
06ae43f34   Al Viro   Don't bother with...
506
  {
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
507
508
509
510
511
512
  	struct kvec iov = {
  		.iov_base	= (void *)buf,
  		.iov_len	= min_t(size_t, count, MAX_RW_COUNT),
  	};
  	struct kiocb kiocb;
  	struct iov_iter iter;
06ae43f34   Al Viro   Don't bother with...
513
  	ssize_t ret;
a01ac27be   Christoph Hellwig   fs: check FMODE_W...
514
515
  	if (WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE)))
  		return -EBADF;
7f7f25e82   Al Viro   replace checking ...
516
  	if (!(file->f_mode & FMODE_CAN_WRITE))
3e84f48ed   Al Viro   vfs/splice: Fix m...
517
  		return -EINVAL;
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
518
519
520
521
522
523
  	/*
  	 * Also fail if ->write_iter and ->write are both wired up as that
  	 * implies very convoluted semantics.
  	 */
  	if (unlikely(!file->f_op->write_iter || file->f_op->write))
  		return warn_unsupported(file, "write");
3e84f48ed   Al Viro   vfs/splice: Fix m...
524

4d03e3cc5   Christoph Hellwig   fs: don't allow k...
525
  	init_sync_kiocb(&kiocb, file);
4c207ef48   Matthew Wilcox (Oracle)   fs: Allow a NULL ...
526
  	kiocb.ki_pos = pos ? *pos : 0;
4d03e3cc5   Christoph Hellwig   fs: don't allow k...
527
528
  	iov_iter_kvec(&iter, WRITE, &iov, 1, iov.iov_len);
  	ret = file->f_op->write_iter(&kiocb, &iter);
06ae43f34   Al Viro   Don't bother with...
529
  	if (ret > 0) {
4c207ef48   Matthew Wilcox (Oracle)   fs: Allow a NULL ...
530
531
  		if (pos)
  			*pos = kiocb.ki_pos;
06ae43f34   Al Viro   Don't bother with...
532
533
534
535
536
537
  		fsnotify_modify(file);
  		add_wchar(current, ret);
  	}
  	inc_syscw(current);
  	return ret;
  }
90fb70279   Linus Torvalds   autofs: use __ker...
538
539
540
541
542
543
544
545
  /*
   * This "EXPORT_SYMBOL_GPL()" is more of a "EXPORT_SYMBOL_DONTUSE()",
   * but autofs is one of the few internal kernel users that actually
   * wants this _and_ can be built as a module. So we need to export
   * this symbol for autofs, even though it really isn't appropriate
   * for any other kernel modules.
   */
  EXPORT_SYMBOL_GPL(__kernel_write);
2ec3a12a6   Al Viro   cachefiles_write_...
546

e13ec939e   Christoph Hellwig   fs: fix kernel_wr...
547
548
  ssize_t kernel_write(struct file *file, const void *buf, size_t count,
  			    loff_t *pos)
ac452acae   Christoph Hellwig   fs: move kernel_w...
549
  {
81238b2cf   Christoph Hellwig   fs: implement ker...
550
  	ssize_t ret;
ac452acae   Christoph Hellwig   fs: move kernel_w...
551

81238b2cf   Christoph Hellwig   fs: implement ker...
552
553
554
  	ret = rw_verify_area(WRITE, file, pos, count);
  	if (ret)
  		return ret;
ac452acae   Christoph Hellwig   fs: move kernel_w...
555

81238b2cf   Christoph Hellwig   fs: implement ker...
556
557
558
559
  	file_start_write(file);
  	ret =  __kernel_write(file, buf, count, pos);
  	file_end_write(file);
  	return ret;
ac452acae   Christoph Hellwig   fs: move kernel_w...
560
561
  }
  EXPORT_SYMBOL(kernel_write);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
567
  ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
  {
  	ssize_t ret;
  
  	if (!(file->f_mode & FMODE_WRITE))
  		return -EBADF;
7f7f25e82   Al Viro   replace checking ...
568
  	if (!(file->f_mode & FMODE_CAN_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  		return -EINVAL;
96d4f267e   Linus Torvalds   Remove 'type' arg...
570
  	if (unlikely(!access_ok(buf, count)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
  		return -EFAULT;
  
  	ret = rw_verify_area(WRITE, file, pos, count);
53ad86266   Christoph Hellwig   fs: remove __vfs_...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  	if (ret)
  		return ret;
  	if (count > MAX_RW_COUNT)
  		count =  MAX_RW_COUNT;
  	file_start_write(file);
  	if (file->f_op->write)
  		ret = file->f_op->write(file, buf, count, pos);
  	else if (file->f_op->write_iter)
  		ret = new_sync_write(file, buf, count, pos);
  	else
  		ret = -EINVAL;
  	if (ret > 0) {
  		fsnotify_modify(file);
  		add_wchar(current, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  	}
53ad86266   Christoph Hellwig   fs: remove __vfs_...
589
590
  	inc_syscw(current);
  	file_end_write(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
  	return ret;
  }
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
593
594
  /* file_ppos returns &file->f_pos or NULL if file is stream */
  static inline loff_t *file_ppos(struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  {
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
596
  	return file->f_mode & FMODE_STREAM ? NULL : &file->f_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  }
3ce4a7bf6   Dominik Brodowski   fs: add ksys_read...
598
  ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  {
9c225f265   Linus Torvalds   vfs: atomic f_pos...
600
  	struct fd f = fdget_pos(fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602

2903ff019   Al Viro   switch simple cas...
603
  	if (f.file) {
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
604
605
606
607
608
609
610
611
  		loff_t pos, *ppos = file_ppos(f.file);
  		if (ppos) {
  			pos = *ppos;
  			ppos = &pos;
  		}
  		ret = vfs_read(f.file, buf, count, ppos);
  		if (ret >= 0 && ppos)
  			f.file->f_pos = pos;
9c225f265   Linus Torvalds   vfs: atomic f_pos...
612
  		fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616

3ce4a7bf6   Dominik Brodowski   fs: add ksys_read...
617
618
619
620
  SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
  {
  	return ksys_read(fd, buf, count);
  }
e7a3e8b2e   Dominik Brodowski   fs: add ksys_writ...
621
  ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  {
9c225f265   Linus Torvalds   vfs: atomic f_pos...
623
  	struct fd f = fdget_pos(fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625

2903ff019   Al Viro   switch simple cas...
626
  	if (f.file) {
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
627
628
629
630
631
632
633
634
  		loff_t pos, *ppos = file_ppos(f.file);
  		if (ppos) {
  			pos = *ppos;
  			ppos = &pos;
  		}
  		ret = vfs_write(f.file, buf, count, ppos);
  		if (ret >= 0 && ppos)
  			f.file->f_pos = pos;
9c225f265   Linus Torvalds   vfs: atomic f_pos...
635
  		fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
  	}
  
  	return ret;
  }
e7a3e8b2e   Dominik Brodowski   fs: add ksys_writ...
640
641
642
643
644
  SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
  		size_t, count)
  {
  	return ksys_write(fd, buf, count);
  }
36028d5dd   Dominik Brodowski   fs: add ksys_p{re...
645
646
  ssize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count,
  		     loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  {
2903ff019   Al Viro   switch simple cas...
648
  	struct fd f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
  
  	if (pos < 0)
  		return -EINVAL;
2903ff019   Al Viro   switch simple cas...
653
654
  	f = fdget(fd);
  	if (f.file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  		ret = -ESPIPE;
2903ff019   Al Viro   switch simple cas...
656
657
658
  		if (f.file->f_mode & FMODE_PREAD)
  			ret = vfs_read(f.file, buf, count, &pos);
  		fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
  	}
  
  	return ret;
  }
36028d5dd   Dominik Brodowski   fs: add ksys_p{re...
663
664
665
666
667
668
669
670
  SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf,
  			size_t, count, loff_t, pos)
  {
  	return ksys_pread64(fd, buf, count, pos);
  }
  
  ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf,
  		      size_t count, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  {
2903ff019   Al Viro   switch simple cas...
672
  	struct fd f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
  
  	if (pos < 0)
  		return -EINVAL;
2903ff019   Al Viro   switch simple cas...
677
678
  	f = fdget(fd);
  	if (f.file) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  		ret = -ESPIPE;
2903ff019   Al Viro   switch simple cas...
680
681
682
  		if (f.file->f_mode & FMODE_PWRITE)  
  			ret = vfs_write(f.file, buf, count, &pos);
  		fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
  	}
  
  	return ret;
  }
36028d5dd   Dominik Brodowski   fs: add ksys_p{re...
687
688
689
690
691
  SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf,
  			 size_t, count, loff_t, pos)
  {
  	return ksys_pwrite64(fd, buf, count, pos);
  }
ac15ac066   Al Viro   lift iov_iter int...
692
  static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
693
  		loff_t *ppos, int type, rwf_t flags)
293bc9822   Al Viro   new methods: ->re...
694
695
  {
  	struct kiocb kiocb;
293bc9822   Al Viro   new methods: ->re...
696
697
698
  	ssize_t ret;
  
  	init_sync_kiocb(&kiocb, filp);
fdd2f5b7d   Goldwyn Rodrigues   fs: Separate out ...
699
700
701
  	ret = kiocb_set_rw_flags(&kiocb, flags);
  	if (ret)
  		return ret;
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
702
  	kiocb.ki_pos = (ppos ? *ppos : 0);
293bc9822   Al Viro   new methods: ->re...
703

0f78d06ac   Miklos Szeredi   vfs: pass type in...
704
  	if (type == READ)
bb7462b6f   Miklos Szeredi   vfs: use helpers ...
705
  		ret = call_read_iter(filp, &kiocb, iter);
0f78d06ac   Miklos Szeredi   vfs: pass type in...
706
  	else
bb7462b6f   Miklos Szeredi   vfs: use helpers ...
707
  		ret = call_write_iter(filp, &kiocb, iter);
599bd19bd   Christoph Hellwig   fs: don't allow t...
708
  	BUG_ON(ret == -EIOCBQUEUED);
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
709
710
  	if (ppos)
  		*ppos = kiocb.ki_pos;
293bc9822   Al Viro   new methods: ->re...
711
712
  	return ret;
  }
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
713
  /* Do it by hand, with file-ops */
ac15ac066   Al Viro   lift iov_iter int...
714
  static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
715
  		loff_t *ppos, int type, rwf_t flags)
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
716
  {
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
717
  	ssize_t ret = 0;
97be7ebe5   Christoph Hellwig   vfs: add the RWF_...
718
  	if (flags & ~RWF_HIPRI)
793b80ef1   Christoph Hellwig   vfs: pass a flags...
719
  		return -EOPNOTSUPP;
ac15ac066   Al Viro   lift iov_iter int...
720
721
  	while (iov_iter_count(iter)) {
  		struct iovec iovec = iov_iter_iovec(iter);
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
722
  		ssize_t nr;
0f78d06ac   Miklos Szeredi   vfs: pass type in...
723
724
725
726
727
728
729
  		if (type == READ) {
  			nr = filp->f_op->read(filp, iovec.iov_base,
  					      iovec.iov_len, ppos);
  		} else {
  			nr = filp->f_op->write(filp, iovec.iov_base,
  					       iovec.iov_len, ppos);
  		}
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
730
731
732
733
734
735
736
  
  		if (nr < 0) {
  			if (!ret)
  				ret = nr;
  			break;
  		}
  		ret += nr;
ac15ac066   Al Viro   lift iov_iter int...
737
  		if (nr != iovec.iov_len)
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
738
  			break;
ac15ac066   Al Viro   lift iov_iter int...
739
  		iov_iter_advance(iter, nr);
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
740
741
742
743
  	}
  
  	return ret;
  }
19c735868   Christoph Hellwig   fs: remove __do_r...
744
  static ssize_t do_iter_read(struct file *file, struct iov_iter *iter,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
745
  		loff_t *pos, rwf_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	size_t tot_len;
7687a7a44   Miklos Szeredi   vfs: extract comm...
748
  	ssize_t ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749

edab5fe38   Christoph Hellwig   fs: move more cod...
750
751
752
753
  	if (!(file->f_mode & FMODE_READ))
  		return -EBADF;
  	if (!(file->f_mode & FMODE_CAN_READ))
  		return -EINVAL;
7687a7a44   Miklos Szeredi   vfs: extract comm...
754
  	tot_len = iov_iter_count(iter);
0504c074b   Al Viro   switch {compat_,}...
755
756
  	if (!tot_len)
  		goto out;
19c735868   Christoph Hellwig   fs: remove __do_r...
757
  	ret = rw_verify_area(READ, file, pos, tot_len);
e28cc7157   Linus Torvalds   Relax the rw_veri...
758
  	if (ret < 0)
19c735868   Christoph Hellwig   fs: remove __do_r...
759
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

19c735868   Christoph Hellwig   fs: remove __do_r...
761
762
  	if (file->f_op->read_iter)
  		ret = do_iter_readv_writev(file, iter, pos, READ, flags);
ee0b3e671   Badari Pulavarty   [PATCH] Remove re...
763
  	else
19c735868   Christoph Hellwig   fs: remove __do_r...
764
  		ret = do_loop_readv_writev(file, iter, pos, READ, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  out:
19c735868   Christoph Hellwig   fs: remove __do_r...
766
767
  	if (ret >= 0)
  		fsnotify_access(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  }
5dcdc43e2   Jiufei Xue   vfs: add vfs_iocb...
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  ssize_t vfs_iocb_iter_read(struct file *file, struct kiocb *iocb,
  			   struct iov_iter *iter)
  {
  	size_t tot_len;
  	ssize_t ret = 0;
  
  	if (!file->f_op->read_iter)
  		return -EINVAL;
  	if (!(file->f_mode & FMODE_READ))
  		return -EBADF;
  	if (!(file->f_mode & FMODE_CAN_READ))
  		return -EINVAL;
  
  	tot_len = iov_iter_count(iter);
  	if (!tot_len)
  		goto out;
  	ret = rw_verify_area(READ, file, &iocb->ki_pos, tot_len);
  	if (ret < 0)
  		return ret;
  
  	ret = call_read_iter(file, iocb, iter);
  out:
  	if (ret >= 0)
  		fsnotify_access(file);
  	return ret;
  }
  EXPORT_SYMBOL(vfs_iocb_iter_read);
18e9710ee   Christoph Hellwig   fs: implement vfs...
797
  ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
798
  		rwf_t flags)
7687a7a44   Miklos Szeredi   vfs: extract comm...
799
  {
18e9710ee   Christoph Hellwig   fs: implement vfs...
800
801
802
803
804
  	if (!file->f_op->read_iter)
  		return -EINVAL;
  	return do_iter_read(file, iter, ppos, flags);
  }
  EXPORT_SYMBOL(vfs_iter_read);
7687a7a44   Miklos Szeredi   vfs: extract comm...
805

19c735868   Christoph Hellwig   fs: remove __do_r...
806
  static ssize_t do_iter_write(struct file *file, struct iov_iter *iter,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
807
  		loff_t *pos, rwf_t flags)
19c735868   Christoph Hellwig   fs: remove __do_r...
808
809
810
  {
  	size_t tot_len;
  	ssize_t ret = 0;
03d95eb2f   Al Viro   lift sb_start_wri...
811

edab5fe38   Christoph Hellwig   fs: move more cod...
812
813
814
815
  	if (!(file->f_mode & FMODE_WRITE))
  		return -EBADF;
  	if (!(file->f_mode & FMODE_CAN_WRITE))
  		return -EINVAL;
19c735868   Christoph Hellwig   fs: remove __do_r...
816
817
818
819
  	tot_len = iov_iter_count(iter);
  	if (!tot_len)
  		return 0;
  	ret = rw_verify_area(WRITE, file, pos, tot_len);
7687a7a44   Miklos Szeredi   vfs: extract comm...
820
821
  	if (ret < 0)
  		return ret;
19c735868   Christoph Hellwig   fs: remove __do_r...
822
823
824
825
  	if (file->f_op->write_iter)
  		ret = do_iter_readv_writev(file, iter, pos, WRITE, flags);
  	else
  		ret = do_loop_readv_writev(file, iter, pos, WRITE, flags);
19c735868   Christoph Hellwig   fs: remove __do_r...
826
827
  	if (ret > 0)
  		fsnotify_modify(file);
7687a7a44   Miklos Szeredi   vfs: extract comm...
828
829
  	return ret;
  }
5dcdc43e2   Jiufei Xue   vfs: add vfs_iocb...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  ssize_t vfs_iocb_iter_write(struct file *file, struct kiocb *iocb,
  			    struct iov_iter *iter)
  {
  	size_t tot_len;
  	ssize_t ret = 0;
  
  	if (!file->f_op->write_iter)
  		return -EINVAL;
  	if (!(file->f_mode & FMODE_WRITE))
  		return -EBADF;
  	if (!(file->f_mode & FMODE_CAN_WRITE))
  		return -EINVAL;
  
  	tot_len = iov_iter_count(iter);
  	if (!tot_len)
  		return 0;
  	ret = rw_verify_area(WRITE, file, &iocb->ki_pos, tot_len);
  	if (ret < 0)
  		return ret;
  
  	ret = call_write_iter(file, iocb, iter);
  	if (ret > 0)
  		fsnotify_modify(file);
  
  	return ret;
  }
  EXPORT_SYMBOL(vfs_iocb_iter_write);
abbb65899   Christoph Hellwig   fs: implement vfs...
857
  ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
858
  		rwf_t flags)
abbb65899   Christoph Hellwig   fs: implement vfs...
859
860
861
862
863
864
  {
  	if (!file->f_op->write_iter)
  		return -EINVAL;
  	return do_iter_write(file, iter, ppos, flags);
  }
  EXPORT_SYMBOL(vfs_iter_write);
36e2c7421   Christoph Hellwig   fs: don't allow s...
865
  static ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
866
  		  unsigned long vlen, loff_t *pos, rwf_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  {
7687a7a44   Miklos Szeredi   vfs: extract comm...
868
869
870
871
  	struct iovec iovstack[UIO_FASTIOV];
  	struct iovec *iov = iovstack;
  	struct iov_iter iter;
  	ssize_t ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872

251b42a1d   Christoph Hellwig   fs: remove do_rea...
873
  	ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
edab5fe38   Christoph Hellwig   fs: move more cod...
874
875
876
877
  	if (ret >= 0) {
  		ret = do_iter_read(file, &iter, pos, flags);
  		kfree(iov);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878

251b42a1d   Christoph Hellwig   fs: remove do_rea...
879
880
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881

9725d4cef   Christoph Hellwig   fs: unexport vfs_...
882
  static ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
883
  		   unsigned long vlen, loff_t *pos, rwf_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
  {
251b42a1d   Christoph Hellwig   fs: remove do_rea...
885
886
887
888
  	struct iovec iovstack[UIO_FASTIOV];
  	struct iovec *iov = iovstack;
  	struct iov_iter iter;
  	ssize_t ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

251b42a1d   Christoph Hellwig   fs: remove do_rea...
890
  	ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
edab5fe38   Christoph Hellwig   fs: move more cod...
891
  	if (ret >= 0) {
62473a2d6   Al Viro   move file_{start,...
892
  		file_start_write(file);
edab5fe38   Christoph Hellwig   fs: move more cod...
893
  		ret = do_iter_write(file, &iter, pos, flags);
62473a2d6   Al Viro   move file_{start,...
894
  		file_end_write(file);
edab5fe38   Christoph Hellwig   fs: move more cod...
895
896
  		kfree(iov);
  	}
251b42a1d   Christoph Hellwig   fs: remove do_rea...
897
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899

f17d8b354   Milosz Tanski   vfs: vfs: Define ...
900
  static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
901
  			unsigned long vlen, rwf_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  {
9c225f265   Linus Torvalds   vfs: atomic f_pos...
903
  	struct fd f = fdget_pos(fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905

2903ff019   Al Viro   switch simple cas...
906
  	if (f.file) {
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
907
908
909
910
911
912
913
914
  		loff_t pos, *ppos = file_ppos(f.file);
  		if (ppos) {
  			pos = *ppos;
  			ppos = &pos;
  		}
  		ret = vfs_readv(f.file, vec, vlen, ppos, flags);
  		if (ret >= 0 && ppos)
  			f.file->f_pos = pos;
9c225f265   Linus Torvalds   vfs: atomic f_pos...
915
  		fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
  	}
  
  	if (ret > 0)
4b98d11b4   Alexey Dobriyan   [PATCH] ifdef ->r...
919
920
  		add_rchar(current, ret);
  	inc_syscr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
  	return ret;
  }
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
923
  static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
924
  			 unsigned long vlen, rwf_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  {
9c225f265   Linus Torvalds   vfs: atomic f_pos...
926
  	struct fd f = fdget_pos(fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  	ssize_t ret = -EBADF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

2903ff019   Al Viro   switch simple cas...
929
  	if (f.file) {
438ab720c   Kirill Smelkov   vfs: pass ppos=NU...
930
931
932
933
934
935
936
937
  		loff_t pos, *ppos = file_ppos(f.file);
  		if (ppos) {
  			pos = *ppos;
  			ppos = &pos;
  		}
  		ret = vfs_writev(f.file, vec, vlen, ppos, flags);
  		if (ret >= 0 && ppos)
  			f.file->f_pos = pos;
9c225f265   Linus Torvalds   vfs: atomic f_pos...
938
  		fdput_pos(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
  	}
  
  	if (ret > 0)
4b98d11b4   Alexey Dobriyan   [PATCH] ifdef ->r...
942
943
  		add_wchar(current, ret);
  	inc_syscw(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
  	return ret;
  }
601cc11d0   Linus Torvalds   Make non-compat p...
946
947
948
949
950
  static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
  {
  #define HALF_LONG_BITS (BITS_PER_LONG / 2)
  	return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
  }
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
951
  static ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
952
  			 unsigned long vlen, loff_t pos, rwf_t flags)
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
953
  {
2903ff019   Al Viro   switch simple cas...
954
  	struct fd f;
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
955
  	ssize_t ret = -EBADF;
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
956
957
958
  
  	if (pos < 0)
  		return -EINVAL;
2903ff019   Al Viro   switch simple cas...
959
960
  	f = fdget(fd);
  	if (f.file) {
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
961
  		ret = -ESPIPE;
2903ff019   Al Viro   switch simple cas...
962
  		if (f.file->f_mode & FMODE_PREAD)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
963
  			ret = vfs_readv(f.file, vec, vlen, &pos, flags);
2903ff019   Al Viro   switch simple cas...
964
  		fdput(f);
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
965
966
967
968
969
970
971
  	}
  
  	if (ret > 0)
  		add_rchar(current, ret);
  	inc_syscr(current);
  	return ret;
  }
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
972
  static ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
973
  			  unsigned long vlen, loff_t pos, rwf_t flags)
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
974
  {
2903ff019   Al Viro   switch simple cas...
975
  	struct fd f;
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
976
  	ssize_t ret = -EBADF;
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
977
978
979
  
  	if (pos < 0)
  		return -EINVAL;
2903ff019   Al Viro   switch simple cas...
980
981
  	f = fdget(fd);
  	if (f.file) {
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
982
  		ret = -ESPIPE;
2903ff019   Al Viro   switch simple cas...
983
  		if (f.file->f_mode & FMODE_PWRITE)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
984
  			ret = vfs_writev(f.file, vec, vlen, &pos, flags);
2903ff019   Al Viro   switch simple cas...
985
  		fdput(f);
f3554f4bc   Gerd Hoffmann   preadv/pwritev: A...
986
987
988
989
990
991
992
  	}
  
  	if (ret > 0)
  		add_wchar(current, ret);
  	inc_syscw(current);
  	return ret;
  }
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen)
  {
  	return do_readv(fd, vec, vlen, 0);
  }
  
  SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen)
  {
  	return do_writev(fd, vec, vlen, 0);
  }
  
  SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
  {
  	loff_t pos = pos_from_hilo(pos_h, pos_l);
  
  	return do_preadv(fd, vec, vlen, pos, 0);
  }
  
  SYSCALL_DEFINE6(preadv2, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1015
  		rwf_t, flags)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  {
  	loff_t pos = pos_from_hilo(pos_h, pos_l);
  
  	if (pos == -1)
  		return do_readv(fd, vec, vlen, flags);
  
  	return do_preadv(fd, vec, vlen, pos, flags);
  }
  
  SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
  {
  	loff_t pos = pos_from_hilo(pos_h, pos_l);
  
  	return do_pwritev(fd, vec, vlen, pos, 0);
  }
  
  SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
  		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1035
  		rwf_t, flags)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1036
1037
1038
1039
1040
1041
1042
1043
  {
  	loff_t pos = pos_from_hilo(pos_h, pos_l);
  
  	if (pos == -1)
  		return do_writev(fd, vec, vlen, flags);
  
  	return do_pwritev(fd, vec, vlen, pos, flags);
  }
3523a9d45   Christoph Hellwig   fs: remove variou...
1044
1045
1046
1047
1048
  /*
   * Various compat syscalls.  Note that they all pretend to take a native
   * iovec - import_iovec will properly treat those as compat_iovecs based on
   * in_compat_syscall().
   */
72ec35163   Al Viro   switch compat rea...
1049
  #ifdef CONFIG_COMPAT
378a10f3a   Heiko Carstens   fs/compat: option...
1050
1051
  #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
  COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1052
  		const struct iovec __user *, vec,
378a10f3a   Heiko Carstens   fs/compat: option...
1053
1054
  		unsigned long, vlen, loff_t, pos)
  {
3523a9d45   Christoph Hellwig   fs: remove variou...
1055
  	return do_preadv(fd, vec, vlen, pos, 0);
378a10f3a   Heiko Carstens   fs/compat: option...
1056
1057
  }
  #endif
dfd948e32   Heiko Carstens   fs/compat: fix pa...
1058
  COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1059
  		const struct iovec __user *, vec,
dfd948e32   Heiko Carstens   fs/compat: fix pa...
1060
  		compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
72ec35163   Al Viro   switch compat rea...
1061
1062
  {
  	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
378a10f3a   Heiko Carstens   fs/compat: option...
1063

3523a9d45   Christoph Hellwig   fs: remove variou...
1064
  	return do_preadv(fd, vec, vlen, pos, 0);
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1065
  }
3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1066
1067
  #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2
  COMPAT_SYSCALL_DEFINE5(preadv64v2, unsigned long, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1068
  		const struct iovec __user *, vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1069
  		unsigned long, vlen, loff_t, pos, rwf_t, flags)
3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1070
  {
cc4b1242d   Aurelien Jarno   vfs: fix preadv64...
1071
  	if (pos == -1)
3523a9d45   Christoph Hellwig   fs: remove variou...
1072
1073
  		return do_readv(fd, vec, vlen, flags);
  	return do_preadv(fd, vec, vlen, pos, flags);
3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1074
1075
  }
  #endif
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1076
  COMPAT_SYSCALL_DEFINE6(preadv2, compat_ulong_t, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1077
  		const struct iovec __user *, vec,
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1078
  		compat_ulong_t, vlen, u32, pos_low, u32, pos_high,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1079
  		rwf_t, flags)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1080
1081
1082
1083
  {
  	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
  
  	if (pos == -1)
3523a9d45   Christoph Hellwig   fs: remove variou...
1084
1085
  		return do_readv(fd, vec, vlen, flags);
  	return do_preadv(fd, vec, vlen, pos, flags);
72ec35163   Al Viro   switch compat rea...
1086
  }
378a10f3a   Heiko Carstens   fs/compat: option...
1087
1088
  #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
  COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1089
  		const struct iovec __user *, vec,
378a10f3a   Heiko Carstens   fs/compat: option...
1090
1091
  		unsigned long, vlen, loff_t, pos)
  {
3523a9d45   Christoph Hellwig   fs: remove variou...
1092
  	return do_pwritev(fd, vec, vlen, pos, 0);
378a10f3a   Heiko Carstens   fs/compat: option...
1093
1094
  }
  #endif
dfd948e32   Heiko Carstens   fs/compat: fix pa...
1095
  COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1096
  		const struct iovec __user *,vec,
dfd948e32   Heiko Carstens   fs/compat: fix pa...
1097
  		compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
72ec35163   Al Viro   switch compat rea...
1098
1099
  {
  	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
378a10f3a   Heiko Carstens   fs/compat: option...
1100

3523a9d45   Christoph Hellwig   fs: remove variou...
1101
  	return do_pwritev(fd, vec, vlen, pos, 0);
72ec35163   Al Viro   switch compat rea...
1102
  }
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1103

3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1104
1105
  #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
  COMPAT_SYSCALL_DEFINE5(pwritev64v2, unsigned long, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1106
  		const struct iovec __user *, vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1107
  		unsigned long, vlen, loff_t, pos, rwf_t, flags)
3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1108
  {
cc4b1242d   Aurelien Jarno   vfs: fix preadv64...
1109
  	if (pos == -1)
3523a9d45   Christoph Hellwig   fs: remove variou...
1110
1111
  		return do_writev(fd, vec, vlen, flags);
  	return do_pwritev(fd, vec, vlen, pos, flags);
3ebfd81f7   H.J. Lu   x86/syscalls: Add...
1112
1113
  }
  #endif
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1114
  COMPAT_SYSCALL_DEFINE6(pwritev2, compat_ulong_t, fd,
3523a9d45   Christoph Hellwig   fs: remove variou...
1115
  		const struct iovec __user *,vec,
ddef7ed2b   Christoph Hellwig   annotate RWF_... ...
1116
  		compat_ulong_t, vlen, u32, pos_low, u32, pos_high, rwf_t, flags)
f17d8b354   Milosz Tanski   vfs: vfs: Define ...
1117
1118
1119
1120
  {
  	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
  
  	if (pos == -1)
3523a9d45   Christoph Hellwig   fs: remove variou...
1121
1122
  		return do_writev(fd, vec, vlen, flags);
  	return do_pwritev(fd, vec, vlen, pos, flags);
72ec35163   Al Viro   switch compat rea...
1123
  }
3523a9d45   Christoph Hellwig   fs: remove variou...
1124
  #endif /* CONFIG_COMPAT */
72ec35163   Al Viro   switch compat rea...
1125

19f4fc3ae   Al Viro   convert sendfile{...
1126
1127
  static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
  		  	   size_t count, loff_t max)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  {
2903ff019   Al Viro   switch simple cas...
1129
1130
  	struct fd in, out;
  	struct inode *in_inode, *out_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  	loff_t pos;
7995bd287   Al Viro   splice: don't pas...
1132
  	loff_t out_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  	ssize_t retval;
2903ff019   Al Viro   switch simple cas...
1134
  	int fl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
1138
1139
  
  	/*
  	 * Get input file, and verify that it is ok..
  	 */
  	retval = -EBADF;
2903ff019   Al Viro   switch simple cas...
1140
1141
  	in = fdget(in_fd);
  	if (!in.file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  		goto out;
2903ff019   Al Viro   switch simple cas...
1143
  	if (!(in.file->f_mode & FMODE_READ))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
  		goto fput_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  	retval = -ESPIPE;
7995bd287   Al Viro   splice: don't pas...
1146
1147
1148
1149
  	if (!ppos) {
  		pos = in.file->f_pos;
  	} else {
  		pos = *ppos;
2903ff019   Al Viro   switch simple cas...
1150
  		if (!(in.file->f_mode & FMODE_PREAD))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  			goto fput_in;
7995bd287   Al Viro   splice: don't pas...
1152
1153
  	}
  	retval = rw_verify_area(READ, in.file, &pos, count);
e28cc7157   Linus Torvalds   Relax the rw_veri...
1154
  	if (retval < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  		goto fput_in;
bc61384dc   Al Viro   rw_verify_area():...
1156
1157
  	if (count > MAX_RW_COUNT)
  		count =  MAX_RW_COUNT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
1162
  	/*
  	 * Get output file, and verify that it is ok..
  	 */
  	retval = -EBADF;
2903ff019   Al Viro   switch simple cas...
1163
1164
  	out = fdget(out_fd);
  	if (!out.file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
  		goto fput_in;
2903ff019   Al Viro   switch simple cas...
1166
  	if (!(out.file->f_mode & FMODE_WRITE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  		goto fput_out;
496ad9aa8   Al Viro   new helper: file_...
1168
1169
  	in_inode = file_inode(in.file);
  	out_inode = file_inode(out.file);
7995bd287   Al Viro   splice: don't pas...
1170
1171
  	out_pos = out.file->f_pos;
  	retval = rw_verify_area(WRITE, out.file, &out_pos, count);
e28cc7157   Linus Torvalds   Relax the rw_veri...
1172
  	if (retval < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  		goto fput_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
  	if (!max)
  		max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
1178
1179
1180
1181
  	if (unlikely(pos + count > max)) {
  		retval = -EOVERFLOW;
  		if (pos >= max)
  			goto fput_out;
  		count = max - pos;
  	}
d96e6e716   Jens Axboe   Remove remnants o...
1182
  	fl = 0;
534f2aaa6   Jens Axboe   sys_sendfile: swi...
1183
  #if 0
d96e6e716   Jens Axboe   Remove remnants o...
1184
1185
1186
1187
1188
1189
  	/*
  	 * We need to debate whether we can enable this or not. The
  	 * man page documents EAGAIN return for the output at least,
  	 * and the application is arguably buggy if it doesn't expect
  	 * EAGAIN on a non-blocking file descriptor.
  	 */
2903ff019   Al Viro   switch simple cas...
1190
  	if (in.file->f_flags & O_NONBLOCK)
d96e6e716   Jens Axboe   Remove remnants o...
1191
  		fl = SPLICE_F_NONBLOCK;
534f2aaa6   Jens Axboe   sys_sendfile: swi...
1192
  #endif
50cd2c577   Al Viro   lift file_*_write...
1193
  	file_start_write(out.file);
7995bd287   Al Viro   splice: don't pas...
1194
  	retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
50cd2c577   Al Viro   lift file_*_write...
1195
  	file_end_write(out.file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  
  	if (retval > 0) {
4b98d11b4   Alexey Dobriyan   [PATCH] ifdef ->r...
1198
1199
  		add_rchar(current, retval);
  		add_wchar(current, retval);
a68c2f12b   Scott Wolchok   sendfile: allows ...
1200
1201
  		fsnotify_access(in.file);
  		fsnotify_modify(out.file);
7995bd287   Al Viro   splice: don't pas...
1202
1203
1204
1205
1206
  		out.file->f_pos = out_pos;
  		if (ppos)
  			*ppos = pos;
  		else
  			in.file->f_pos = pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208

4b98d11b4   Alexey Dobriyan   [PATCH] ifdef ->r...
1209
1210
  	inc_syscr(current);
  	inc_syscw(current);
7995bd287   Al Viro   splice: don't pas...
1211
  	if (pos > max)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
1213
1214
  		retval = -EOVERFLOW;
  
  fput_out:
2903ff019   Al Viro   switch simple cas...
1215
  	fdput(out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  fput_in:
2903ff019   Al Viro   switch simple cas...
1217
  	fdput(in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
  out:
  	return retval;
  }
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
1221
  SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  {
  	loff_t pos;
  	off_t off;
  	ssize_t ret;
  
  	if (offset) {
  		if (unlikely(get_user(off, offset)))
  			return -EFAULT;
  		pos = off;
  		ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
  		if (unlikely(put_user(pos, offset)))
  			return -EFAULT;
  		return ret;
  	}
  
  	return do_sendfile(out_fd, in_fd, NULL, count, 0);
  }
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
1239
  SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  {
  	loff_t pos;
  	ssize_t ret;
  
  	if (offset) {
  		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
  			return -EFAULT;
  		ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
  		if (unlikely(put_user(pos, offset)))
  			return -EFAULT;
  		return ret;
  	}
  
  	return do_sendfile(out_fd, in_fd, NULL, count, 0);
  }
19f4fc3ae   Al Viro   convert sendfile{...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  
  #ifdef CONFIG_COMPAT
  COMPAT_SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd,
  		compat_off_t __user *, offset, compat_size_t, count)
  {
  	loff_t pos;
  	off_t off;
  	ssize_t ret;
  
  	if (offset) {
  		if (unlikely(get_user(off, offset)))
  			return -EFAULT;
  		pos = off;
  		ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
  		if (unlikely(put_user(pos, offset)))
  			return -EFAULT;
  		return ret;
  	}
  
  	return do_sendfile(out_fd, in_fd, NULL, count, 0);
  }
  
  COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
  		compat_loff_t __user *, offset, compat_size_t, count)
  {
  	loff_t pos;
  	ssize_t ret;
  
  	if (offset) {
  		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
  			return -EFAULT;
  		ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
  		if (unlikely(put_user(pos, offset)))
  			return -EFAULT;
  		return ret;
  	}
  
  	return do_sendfile(out_fd, in_fd, NULL, count, 0);
  }
  #endif
29732938a   Zach Brown   vfs: add copy_fil...
1295

f16acc9d9   Dave Chinner   vfs: introduce ge...
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  /**
   * generic_copy_file_range - copy data between two files
   * @file_in:	file structure to read from
   * @pos_in:	file offset to read from
   * @file_out:	file structure to write data to
   * @pos_out:	file offset to write data to
   * @len:	amount of data to copy
   * @flags:	copy flags
   *
   * This is a generic filesystem helper to copy data from one file to another.
   * It has no constraints on the source or destination file owners - the files
   * can belong to different superblocks and different filesystem types. Short
   * copies are allowed.
   *
   * This should be called from the @file_out filesystem, as per the
   * ->copy_file_range() method.
   *
   * Returns the number of bytes copied or a negative error indicating the
   * failure.
   */
  
  ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
  				struct file *file_out, loff_t pos_out,
  				size_t len, unsigned int flags)
  {
  	return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
  				len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
  }
  EXPORT_SYMBOL(generic_copy_file_range);
64bf5ff58   Dave Chinner   vfs: no fallback ...
1325
1326
1327
1328
  static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
  				  struct file *file_out, loff_t pos_out,
  				  size_t len, unsigned int flags)
  {
5dae222a5   Amir Goldstein   vfs: allow copy_f...
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
  	/*
  	 * Although we now allow filesystems to handle cross sb copy, passing
  	 * a file of the wrong filesystem type to filesystem driver can result
  	 * in an attempt to dereference the wrong type of ->private_data, so
  	 * avoid doing that until we really have a good reason.  NFS defines
  	 * several different file_system_type structures, but they all end up
  	 * using the same ->copy_file_range() function pointer.
  	 */
  	if (file_out->f_op->copy_file_range &&
  	    file_out->f_op->copy_file_range == file_in->f_op->copy_file_range)
64bf5ff58   Dave Chinner   vfs: no fallback ...
1339
1340
1341
1342
1343
1344
1345
  		return file_out->f_op->copy_file_range(file_in, pos_in,
  						       file_out, pos_out,
  						       len, flags);
  
  	return generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
  				       flags);
  }
29732938a   Zach Brown   vfs: add copy_fil...
1346
  /*
407e9c63e   Darrick J. Wong   vfs: move the gen...
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
   * Performs necessary checks before doing a file copy
   *
   * Can adjust amount of bytes to copy via @req_count argument.
   * Returns appropriate error code that caller should return or
   * zero in case the copy should be allowed.
   */
  static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
  				    struct file *file_out, loff_t pos_out,
  				    size_t *req_count, unsigned int flags)
  {
  	struct inode *inode_in = file_inode(file_in);
  	struct inode *inode_out = file_inode(file_out);
  	uint64_t count = *req_count;
  	loff_t size_in;
  	int ret;
  
  	ret = generic_file_rw_checks(file_in, file_out);
  	if (ret)
  		return ret;
  
  	/* Don't touch certain kinds of inodes */
  	if (IS_IMMUTABLE(inode_out))
  		return -EPERM;
  
  	if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
  		return -ETXTBSY;
  
  	/* Ensure offsets don't wrap. */
  	if (pos_in + count < pos_in || pos_out + count < pos_out)
  		return -EOVERFLOW;
  
  	/* Shorten the copy to EOF */
  	size_in = i_size_read(inode_in);
  	if (pos_in >= size_in)
  		count = 0;
  	else
  		count = min(count, size_in - (uint64_t)pos_in);
  
  	ret = generic_write_check_limits(file_out, pos_out, &count);
  	if (ret)
  		return ret;
  
  	/* Don't allow overlapped copying within the same file. */
  	if (inode_in == inode_out &&
  	    pos_out + count > pos_in &&
  	    pos_out < pos_in + count)
  		return -EINVAL;
  
  	*req_count = count;
  	return 0;
  }
  
  /*
29732938a   Zach Brown   vfs: add copy_fil...
1400
1401
1402
1403
1404
1405
1406
1407
   * copy_file_range() differs from regular file read and write in that it
   * specifically allows return partial success.  When it does so is up to
   * the copy_file_range method.
   */
  ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
  			    struct file *file_out, loff_t pos_out,
  			    size_t len, unsigned int flags)
  {
29732938a   Zach Brown   vfs: add copy_fil...
1408
1409
1410
1411
  	ssize_t ret;
  
  	if (flags != 0)
  		return -EINVAL;
96e6e8f4a   Amir Goldstein   vfs: add missing ...
1412
1413
  	ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
  				       flags);
a31713517   Amir Goldstein   vfs: introduce ge...
1414
1415
  	if (unlikely(ret))
  		return ret;
11cbfb107   Amir Goldstein   vfs: deny copy_fi...
1416

29732938a   Zach Brown   vfs: add copy_fil...
1417
  	ret = rw_verify_area(READ, file_in, &pos_in, len);
bc61384dc   Al Viro   rw_verify_area():...
1418
1419
1420
1421
1422
  	if (unlikely(ret))
  		return ret;
  
  	ret = rw_verify_area(WRITE, file_out, &pos_out, len);
  	if (unlikely(ret))
29732938a   Zach Brown   vfs: add copy_fil...
1423
  		return ret;
29732938a   Zach Brown   vfs: add copy_fil...
1424
1425
  	if (len == 0)
  		return 0;
bfe219d37   Amir Goldstein   vfs: wrap write f...
1426
  	file_start_write(file_out);
29732938a   Zach Brown   vfs: add copy_fil...
1427

a76b5b043   Christoph Hellwig   fs: try to clone ...
1428
1429
1430
1431
  	/*
  	 * Try cloning first, this is supported by more file systems, and
  	 * more efficient if both clone and copy are supported (e.g. NFS).
  	 */
5dae222a5   Amir Goldstein   vfs: allow copy_f...
1432
1433
  	if (file_in->f_op->remap_file_range &&
  	    file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
42ec3d4c0   Darrick J. Wong   vfs: make remap_f...
1434
1435
1436
1437
  		loff_t cloned;
  
  		cloned = file_in->f_op->remap_file_range(file_in, pos_in,
  				file_out, pos_out,
eca3654e3   Darrick J. Wong   vfs: enable remap...
1438
1439
  				min_t(loff_t, MAX_RW_COUNT, len),
  				REMAP_FILE_CAN_SHORTEN);
42ec3d4c0   Darrick J. Wong   vfs: make remap_f...
1440
1441
  		if (cloned > 0) {
  			ret = cloned;
a76b5b043   Christoph Hellwig   fs: try to clone ...
1442
1443
1444
  			goto done;
  		}
  	}
64bf5ff58   Dave Chinner   vfs: no fallback ...
1445
1446
1447
  	ret = do_copy_file_range(file_in, pos_in, file_out, pos_out, len,
  				flags);
  	WARN_ON_ONCE(ret == -EOPNOTSUPP);
a76b5b043   Christoph Hellwig   fs: try to clone ...
1448
  done:
29732938a   Zach Brown   vfs: add copy_fil...
1449
1450
1451
1452
1453
1454
  	if (ret > 0) {
  		fsnotify_access(file_in);
  		add_rchar(current, ret);
  		fsnotify_modify(file_out);
  		add_wchar(current, ret);
  	}
a76b5b043   Christoph Hellwig   fs: try to clone ...
1455

29732938a   Zach Brown   vfs: add copy_fil...
1456
1457
  	inc_syscr(current);
  	inc_syscw(current);
bfe219d37   Amir Goldstein   vfs: wrap write f...
1458
  	file_end_write(file_out);
29732938a   Zach Brown   vfs: add copy_fil...
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
  
  	return ret;
  }
  EXPORT_SYMBOL(vfs_copy_file_range);
  
  SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
  		int, fd_out, loff_t __user *, off_out,
  		size_t, len, unsigned int, flags)
  {
  	loff_t pos_in;
  	loff_t pos_out;
  	struct fd f_in;
  	struct fd f_out;
  	ssize_t ret = -EBADF;
  
  	f_in = fdget(fd_in);
  	if (!f_in.file)
  		goto out2;
  
  	f_out = fdget(fd_out);
  	if (!f_out.file)
  		goto out1;
  
  	ret = -EFAULT;
  	if (off_in) {
  		if (copy_from_user(&pos_in, off_in, sizeof(loff_t)))
  			goto out;
  	} else {
  		pos_in = f_in.file->f_pos;
  	}
  
  	if (off_out) {
  		if (copy_from_user(&pos_out, off_out, sizeof(loff_t)))
  			goto out;
  	} else {
  		pos_out = f_out.file->f_pos;
  	}
  
  	ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
  				  flags);
  	if (ret > 0) {
  		pos_in += ret;
  		pos_out += ret;
  
  		if (off_in) {
  			if (copy_to_user(off_in, &pos_in, sizeof(loff_t)))
  				ret = -EFAULT;
  		} else {
  			f_in.file->f_pos = pos_in;
  		}
  
  		if (off_out) {
  			if (copy_to_user(off_out, &pos_out, sizeof(loff_t)))
  				ret = -EFAULT;
  		} else {
  			f_out.file->f_pos = pos_out;
  		}
  	}
  
  out:
  	fdput(f_out);
  out1:
  	fdput(f_in);
  out2:
  	return ret;
  }
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
1525

c32e5f399   Darrick J. Wong   vfs: hide file ra...
1526
  /*
407e9c63e   Darrick J. Wong   vfs: move the gen...
1527
1528
1529
   * Don't operate on ranges the page cache doesn't support, and don't exceed the
   * LFS limits.  If pos is under the limit it becomes a short access.  If it
   * exceeds the limit we return -EFBIG.
edc58dd01   Darrick J. Wong   vfs: fix page loc...
1530
   */
407e9c63e   Darrick J. Wong   vfs: move the gen...
1531
  int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count)
edc58dd01   Darrick J. Wong   vfs: fix page loc...
1532
  {
407e9c63e   Darrick J. Wong   vfs: move the gen...
1533
1534
1535
  	struct inode *inode = file->f_mapping->host;
  	loff_t max_size = inode->i_sb->s_maxbytes;
  	loff_t limit = rlimit(RLIMIT_FSIZE);
edc58dd01   Darrick J. Wong   vfs: fix page loc...
1536

407e9c63e   Darrick J. Wong   vfs: move the gen...
1537
1538
1539
1540
  	if (limit != RLIM_INFINITY) {
  		if (pos >= limit) {
  			send_sig(SIGXFSZ, current, 0);
  			return -EFBIG;
edc58dd01   Darrick J. Wong   vfs: fix page loc...
1541
  		}
407e9c63e   Darrick J. Wong   vfs: move the gen...
1542
1543
  		*count = min(*count, limit - pos);
  	}
edc58dd01   Darrick J. Wong   vfs: fix page loc...
1544

407e9c63e   Darrick J. Wong   vfs: move the gen...
1545
1546
  	if (!(file->f_flags & O_LARGEFILE))
  		max_size = MAX_NON_LFS;
c32e5f399   Darrick J. Wong   vfs: hide file ra...
1547

407e9c63e   Darrick J. Wong   vfs: move the gen...
1548
1549
  	if (unlikely(pos >= max_size))
  		return -EFBIG;
c32e5f399   Darrick J. Wong   vfs: hide file ra...
1550

407e9c63e   Darrick J. Wong   vfs: move the gen...
1551
  	*count = min(*count, max_size - pos);
c32e5f399   Darrick J. Wong   vfs: hide file ra...
1552

c32e5f399   Darrick J. Wong   vfs: hide file ra...
1553
  	return 0;
c32e5f399   Darrick J. Wong   vfs: hide file ra...
1554
  }
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
1555

876bec6f9   Darrick J. Wong   vfs: refactor clo...
1556
  /*
407e9c63e   Darrick J. Wong   vfs: move the gen...
1557
   * Performs necessary checks before doing a write
22725ce4e   Darrick J. Wong   vfs: fix isize/po...
1558
   *
407e9c63e   Darrick J. Wong   vfs: move the gen...
1559
1560
1561
   * Can adjust writing position or amount of bytes to write.
   * Returns appropriate error code that caller should return or
   * zero in case that write should be allowed.
876bec6f9   Darrick J. Wong   vfs: refactor clo...
1562
   */
407e9c63e   Darrick J. Wong   vfs: move the gen...
1563
  ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
876bec6f9   Darrick J. Wong   vfs: refactor clo...
1564
  {
407e9c63e   Darrick J. Wong   vfs: move the gen...
1565
1566
1567
  	struct file *file = iocb->ki_filp;
  	struct inode *inode = file->f_mapping->host;
  	loff_t count;
876bec6f9   Darrick J. Wong   vfs: refactor clo...
1568
  	int ret;
407e9c63e   Darrick J. Wong   vfs: move the gen...
1569
  	if (IS_SWAPFILE(inode))
876bec6f9   Darrick J. Wong   vfs: refactor clo...
1570
  		return -ETXTBSY;
407e9c63e   Darrick J. Wong   vfs: move the gen...
1571
1572
  	if (!iov_iter_count(from))
  		return 0;
5de4480ae   Mark Fasheh   vfs: allow dedupe...
1573

407e9c63e   Darrick J. Wong   vfs: move the gen...
1574
1575
1576
  	/* FIXME: this is for backwards compatibility with 2.4 */
  	if (iocb->ki_flags & IOCB_APPEND)
  		iocb->ki_pos = i_size_read(inode);
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1577

407e9c63e   Darrick J. Wong   vfs: move the gen...
1578
1579
  	if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
  		return -EINVAL;
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1580

407e9c63e   Darrick J. Wong   vfs: move the gen...
1581
1582
  	count = iov_iter_count(from);
  	ret = generic_write_check_limits(file, iocb->ki_pos, &count);
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1583
1584
  	if (ret)
  		return ret;
407e9c63e   Darrick J. Wong   vfs: move the gen...
1585
1586
  	iov_iter_truncate(from, count);
  	return iov_iter_count(from);
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1587
  }
407e9c63e   Darrick J. Wong   vfs: move the gen...
1588
  EXPORT_SYMBOL(generic_write_checks);
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1589

407e9c63e   Darrick J. Wong   vfs: move the gen...
1590
1591
1592
1593
1594
  /*
   * Performs common checks before doing a file copy/clone
   * from @file_in to @file_out.
   */
  int generic_file_rw_checks(struct file *file_in, struct file *file_out)
54dbc1517   Darrick J. Wong   vfs: hoist the bt...
1595
  {
407e9c63e   Darrick J. Wong   vfs: move the gen...
1596
1597
  	struct inode *inode_in = file_inode(file_in);
  	struct inode *inode_out = file_inode(file_out);
54dbc1517   Darrick J. Wong   vfs: hoist the bt...
1598

407e9c63e   Darrick J. Wong   vfs: move the gen...
1599
1600
  	/* Don't copy dirs, pipes, sockets... */
  	if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
494633fac   Dave Chinner   vfs: vfs_dedupe_f...
1601
  		return -EISDIR;
407e9c63e   Darrick J. Wong   vfs: move the gen...
1602
  	if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
22725ce4e   Darrick J. Wong   vfs: fix isize/po...
1603
  		return -EINVAL;
407e9c63e   Darrick J. Wong   vfs: move the gen...
1604
1605
1606
1607
  	if (!(file_in->f_mode & FMODE_READ) ||
  	    !(file_out->f_mode & FMODE_WRITE) ||
  	    (file_out->f_flags & O_APPEND))
  		return -EBADF;
1b4f42a1e   Miklos Szeredi   vfs: dedupe: extr...
1608

407e9c63e   Darrick J. Wong   vfs: move the gen...
1609
  	return 0;
54dbc1517   Darrick J. Wong   vfs: hoist the bt...
1610
  }