Blame view
fs/read_write.c
30.2 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 |
/* * linux/fs/read_write.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <linux/slab.h> #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/file.h> #include <linux/uio.h> |
a27bb332c aio: don't includ... |
12 |
#include <linux/aio.h> |
0eeca2830 [PATCH] inotify |
13 |
#include <linux/fsnotify.h> |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include <linux/security.h> |
630d9c472 fs: reduce the us... |
15 |
#include <linux/export.h> |
1da177e4c Linux-2.6.12-rc2 |
16 |
#include <linux/syscalls.h> |
e28cc7157 Relax the rw_veri... |
17 |
#include <linux/pagemap.h> |
d6b29d7ce splice: divorce t... |
18 |
#include <linux/splice.h> |
561c67319 switch lseek to C... |
19 |
#include <linux/compat.h> |
06ae43f34 Don't bother with... |
20 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
21 22 23 |
#include <asm/uaccess.h> #include <asm/unistd.h> |
c0bd14af5 kill fs/read_write.h |
24 25 26 |
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *, unsigned long, loff_t); |
293bc9822 new methods: ->re... |
27 |
typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); |
c0bd14af5 kill fs/read_write.h |
28 |
|
4b6f5d20b [PATCH] Make most... |
29 |
const struct file_operations generic_ro_fops = { |
1da177e4c Linux-2.6.12-rc2 |
30 |
.llseek = generic_file_llseek, |
aad4f8bb4 switch simple gen... |
31 32 |
.read = new_sync_read, .read_iter = generic_file_read_iter, |
1da177e4c Linux-2.6.12-rc2 |
33 |
.mmap = generic_file_readonly_mmap, |
534f2aaa6 sys_sendfile: swi... |
34 |
.splice_read = generic_file_splice_read, |
1da177e4c Linux-2.6.12-rc2 |
35 36 37 |
}; EXPORT_SYMBOL(generic_ro_fops); |
cccb5a1e6 fix signedness me... |
38 |
static inline int unsigned_offsets(struct file *file) |
4a3956c79 vfs: introduce FM... |
39 |
{ |
cccb5a1e6 fix signedness me... |
40 |
return file->f_mode & FMODE_UNSIGNED_OFFSET; |
4a3956c79 vfs: introduce FM... |
41 |
} |
46a1c2c7a vfs: export lseek... |
42 43 44 45 46 47 48 49 50 51 52 53 54 |
/** * 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 vfs: do (nearly) ... |
55 56 57 58 59 60 61 62 63 64 65 66 |
{ 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 vfs: export lseek... |
67 |
EXPORT_SYMBOL(vfs_setpos); |
ef3d0fd27 vfs: do (nearly) ... |
68 |
|
3a8cff4f0 [PATCH] generic_f... |
69 |
/** |
5760495a8 vfs: add generic_... |
70 |
* generic_file_llseek_size - generic llseek implementation for regular files |
3a8cff4f0 [PATCH] generic_f... |
71 72 |
* @file: file structure to seek on * @offset: file offset to seek to |
965c8e59c lseek: the "whenc... |
73 |
* @whence: type of seek |
e8b96eb50 vfs: allow custom... |
74 75 |
* @size: max size of this file in file system * @eof: offset used for SEEK_END position |
3a8cff4f0 [PATCH] generic_f... |
76 |
* |
5760495a8 vfs: add generic_... |
77 |
* This is a variant of generic_file_llseek that allows passing in a custom |
e8b96eb50 vfs: allow custom... |
78 |
* maximum file size and a custom EOF position, for e.g. hashed directories |
ef3d0fd27 vfs: do (nearly) ... |
79 80 |
* * Synchronization: |
5760495a8 vfs: add generic_... |
81 |
* SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms) |
ef3d0fd27 vfs: do (nearly) ... |
82 83 |
* SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes. * read/writes behave like SEEK_SET against seeks. |
3a8cff4f0 [PATCH] generic_f... |
84 |
*/ |
9465efc9e Remove BKL from r... |
85 |
loff_t |
965c8e59c lseek: the "whenc... |
86 |
generic_file_llseek_size(struct file *file, loff_t offset, int whence, |
e8b96eb50 vfs: allow custom... |
87 |
loff_t maxsize, loff_t eof) |
1da177e4c Linux-2.6.12-rc2 |
88 |
{ |
965c8e59c lseek: the "whenc... |
89 |
switch (whence) { |
3a8cff4f0 [PATCH] generic_f... |
90 |
case SEEK_END: |
e8b96eb50 vfs: allow custom... |
91 |
offset += eof; |
3a8cff4f0 [PATCH] generic_f... |
92 93 |
break; case SEEK_CUR: |
5b6f1eb97 vfs: lseek(fd, 0,... |
94 95 96 97 98 99 100 101 |
/* * 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 vfs: do (nearly) ... |
102 103 104 105 106 107 |
/* * 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 vfs: export lseek... |
108 |
offset = vfs_setpos(file, file->f_pos + offset, maxsize); |
ef3d0fd27 vfs: do (nearly) ... |
109 110 |
spin_unlock(&file->f_lock); return offset; |
982d81658 fs: add SEEK_HOLE... |
111 112 113 114 115 |
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. */ |
e8b96eb50 vfs: allow custom... |
116 |
if (offset >= eof) |
982d81658 fs: add SEEK_HOLE... |
117 118 119 120 121 122 123 |
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. */ |
e8b96eb50 vfs: allow custom... |
124 |
if (offset >= eof) |
982d81658 fs: add SEEK_HOLE... |
125 |
return -ENXIO; |
e8b96eb50 vfs: allow custom... |
126 |
offset = eof; |
982d81658 fs: add SEEK_HOLE... |
127 |
break; |
1da177e4c Linux-2.6.12-rc2 |
128 |
} |
3a8cff4f0 [PATCH] generic_f... |
129 |
|
46a1c2c7a vfs: export lseek... |
130 |
return vfs_setpos(file, offset, maxsize); |
5760495a8 vfs: add generic_... |
131 132 133 134 135 136 137 |
} 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 lseek: the "whenc... |
138 |
* @whence: type of seek |
5760495a8 vfs: add generic_... |
139 140 141 |
* * 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 fs/read_write.c: ... |
142 |
* @offset and @whence. |
5760495a8 vfs: add generic_... |
143 |
*/ |
965c8e59c lseek: the "whenc... |
144 |
loff_t generic_file_llseek(struct file *file, loff_t offset, int whence) |
5760495a8 vfs: add generic_... |
145 146 |
{ struct inode *inode = file->f_mapping->host; |
965c8e59c lseek: the "whenc... |
147 |
return generic_file_llseek_size(file, offset, whence, |
e8b96eb50 vfs: allow custom... |
148 149 |
inode->i_sb->s_maxbytes, i_size_read(inode)); |
1da177e4c Linux-2.6.12-rc2 |
150 |
} |
9465efc9e Remove BKL from r... |
151 |
EXPORT_SYMBOL(generic_file_llseek); |
1da177e4c Linux-2.6.12-rc2 |
152 |
|
ae6afc3f5 vfs: introduce no... |
153 |
/** |
1bf9d14df new helper: fixed... |
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
* 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); /** |
ae6afc3f5 vfs: introduce no... |
174 175 176 |
* noop_llseek - No Operation Performed llseek implementation * @file: file structure to seek on * @offset: file offset to seek to |
965c8e59c lseek: the "whenc... |
177 |
* @whence: type of seek |
ae6afc3f5 vfs: introduce no... |
178 179 180 181 182 183 |
* * 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 lseek: the "whenc... |
184 |
loff_t noop_llseek(struct file *file, loff_t offset, int whence) |
ae6afc3f5 vfs: introduce no... |
185 186 187 188 |
{ return file->f_pos; } EXPORT_SYMBOL(noop_llseek); |
965c8e59c lseek: the "whenc... |
189 |
loff_t no_llseek(struct file *file, loff_t offset, int whence) |
1da177e4c Linux-2.6.12-rc2 |
190 191 192 193 |
{ return -ESPIPE; } EXPORT_SYMBOL(no_llseek); |
965c8e59c lseek: the "whenc... |
194 |
loff_t default_llseek(struct file *file, loff_t offset, int whence) |
1da177e4c Linux-2.6.12-rc2 |
195 |
{ |
496ad9aa8 new helper: file_... |
196 |
struct inode *inode = file_inode(file); |
16abef0e9 fs: use loff_t ty... |
197 |
loff_t retval; |
1da177e4c Linux-2.6.12-rc2 |
198 |
|
982d81658 fs: add SEEK_HOLE... |
199 |
mutex_lock(&inode->i_mutex); |
965c8e59c lseek: the "whenc... |
200 |
switch (whence) { |
7b8e89249 use symbolic cons... |
201 |
case SEEK_END: |
982d81658 fs: add SEEK_HOLE... |
202 |
offset += i_size_read(inode); |
1da177e4c Linux-2.6.12-rc2 |
203 |
break; |
7b8e89249 use symbolic cons... |
204 |
case SEEK_CUR: |
5b6f1eb97 vfs: lseek(fd, 0,... |
205 206 207 208 |
if (offset == 0) { retval = file->f_pos; goto out; } |
1da177e4c Linux-2.6.12-rc2 |
209 |
offset += file->f_pos; |
982d81658 fs: add SEEK_HOLE... |
210 211 212 213 214 215 216 |
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 fs: add missing u... |
217 218 219 220 |
if (offset >= inode->i_size) { retval = -ENXIO; goto out; } |
982d81658 fs: add SEEK_HOLE... |
221 222 223 224 225 226 227 |
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 fs: add missing u... |
228 229 230 231 |
if (offset >= inode->i_size) { retval = -ENXIO; goto out; } |
982d81658 fs: add SEEK_HOLE... |
232 233 |
offset = inode->i_size; break; |
1da177e4c Linux-2.6.12-rc2 |
234 235 |
} retval = -EINVAL; |
cccb5a1e6 fix signedness me... |
236 |
if (offset >= 0 || unsigned_offsets(file)) { |
1da177e4c Linux-2.6.12-rc2 |
237 238 239 240 241 242 |
if (offset != file->f_pos) { file->f_pos = offset; file->f_version = 0; } retval = offset; } |
5b6f1eb97 vfs: lseek(fd, 0,... |
243 |
out: |
982d81658 fs: add SEEK_HOLE... |
244 |
mutex_unlock(&inode->i_mutex); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 |
return retval; } EXPORT_SYMBOL(default_llseek); |
965c8e59c lseek: the "whenc... |
248 |
loff_t vfs_llseek(struct file *file, loff_t offset, int whence) |
1da177e4c Linux-2.6.12-rc2 |
249 250 251 252 253 |
{ loff_t (*fn)(struct file *, loff_t, int); fn = no_llseek; if (file->f_mode & FMODE_LSEEK) { |
72c2d5319 file->f_op is nev... |
254 |
if (file->f_op->llseek) |
1da177e4c Linux-2.6.12-rc2 |
255 256 |
fn = file->f_op->llseek; } |
965c8e59c lseek: the "whenc... |
257 |
return fn(file, offset, whence); |
1da177e4c Linux-2.6.12-rc2 |
258 259 |
} EXPORT_SYMBOL(vfs_llseek); |
9c225f265 vfs: atomic f_pos... |
260 261 |
static inline struct fd fdget_pos(int fd) { |
bd2a31d52 get rid of fget_l... |
262 |
return __to_fd(__fdget_pos(fd)); |
9c225f265 vfs: atomic f_pos... |
263 264 265 266 267 268 269 270 |
} static inline void fdput_pos(struct fd f) { if (f.flags & FDPUT_POS_UNLOCK) mutex_unlock(&f.file->f_pos_lock); fdput(f); } |
965c8e59c lseek: the "whenc... |
271 |
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) |
1da177e4c Linux-2.6.12-rc2 |
272 273 |
{ off_t retval; |
9c225f265 vfs: atomic f_pos... |
274 |
struct fd f = fdget_pos(fd); |
2903ff019 switch simple cas... |
275 276 |
if (!f.file) return -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
277 278 |
retval = -EINVAL; |
965c8e59c lseek: the "whenc... |
279 280 |
if (whence <= SEEK_MAX) { loff_t res = vfs_llseek(f.file, offset, whence); |
1da177e4c Linux-2.6.12-rc2 |
281 282 283 284 |
retval = res; if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } |
9c225f265 vfs: atomic f_pos... |
285 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
286 287 |
return retval; } |
561c67319 switch lseek to C... |
288 289 290 291 292 293 |
#ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned int, whence) { return sys_lseek(fd, offset, whence); } #endif |
1da177e4c Linux-2.6.12-rc2 |
294 |
#ifdef __ARCH_WANT_SYS_LLSEEK |
003d7ab47 [CVE-2009-0029] S... |
295 296 |
SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, unsigned long, offset_low, loff_t __user *, result, |
965c8e59c lseek: the "whenc... |
297 |
unsigned int, whence) |
1da177e4c Linux-2.6.12-rc2 |
298 299 |
{ int retval; |
d7a15f8d0 vfs: atomic f_pos... |
300 |
struct fd f = fdget_pos(fd); |
1da177e4c Linux-2.6.12-rc2 |
301 |
loff_t offset; |
1da177e4c Linux-2.6.12-rc2 |
302 |
|
2903ff019 switch simple cas... |
303 304 |
if (!f.file) return -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
305 306 |
retval = -EINVAL; |
965c8e59c lseek: the "whenc... |
307 |
if (whence > SEEK_MAX) |
1da177e4c Linux-2.6.12-rc2 |
308 |
goto out_putf; |
2903ff019 switch simple cas... |
309 |
offset = vfs_llseek(f.file, ((loff_t) offset_high << 32) | offset_low, |
965c8e59c lseek: the "whenc... |
310 |
whence); |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 314 315 316 317 318 |
retval = (int)offset; if (offset >= 0) { retval = -EFAULT; if (!copy_to_user(result, &offset, sizeof(offset))) retval = 0; } out_putf: |
d7a15f8d0 vfs: atomic f_pos... |
319 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 |
return retval; } #endif |
e28cc7157 Relax the rw_veri... |
323 324 325 326 327 |
/* * rw_verify_area doesn't like huge counts. We limit * them to something that fits in "int" so that others * won't have to do range checks all the time. */ |
68d70d03f constify rw_verif... |
328 |
int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
329 330 331 |
{ struct inode *inode; loff_t pos; |
c43e259cc security: call se... |
332 |
int retval = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
333 |
|
496ad9aa8 new helper: file_... |
334 |
inode = file_inode(file); |
e28cc7157 Relax the rw_veri... |
335 |
if (unlikely((ssize_t) count < 0)) |
c43e259cc security: call se... |
336 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
337 |
pos = *ppos; |
cccb5a1e6 fix signedness me... |
338 339 340 341 342 343 344 |
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)) |
4a3956c79 vfs: introduce FM... |
345 346 |
return retval; } |
1da177e4c Linux-2.6.12-rc2 |
347 |
|
a16877ca9 Cleanup macros fo... |
348 |
if (unlikely(inode->i_flock && mandatory_lock(inode))) { |
c43e259cc security: call se... |
349 |
retval = locks_mandatory_area( |
e28cc7157 Relax the rw_veri... |
350 351 352 353 354 |
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, pos, count); if (retval < 0) return retval; } |
c43e259cc security: call se... |
355 356 357 358 |
retval = security_file_permission(file, read_write == READ ? MAY_READ : MAY_WRITE); if (retval) return retval; |
e28cc7157 Relax the rw_veri... |
359 |
return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; |
1da177e4c Linux-2.6.12-rc2 |
360 361 362 363 |
} ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { |
027445c37 [PATCH] Vectorize... |
364 |
struct iovec iov = { .iov_base = buf, .iov_len = len }; |
1da177e4c Linux-2.6.12-rc2 |
365 366 367 368 369 |
struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; |
61964eba5 do_sync_read/writ... |
370 |
kiocb.ki_nbytes = len; |
027445c37 [PATCH] Vectorize... |
371 |
|
41003a7bc aio: remove retry... |
372 |
ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos); |
1da177e4c Linux-2.6.12-rc2 |
373 374 375 376 377 378 379 |
if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } EXPORT_SYMBOL(do_sync_read); |
293bc9822 new methods: ->re... |
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { struct iovec iov = { .iov_base = buf, .iov_len = len }; struct kiocb kiocb; struct iov_iter iter; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_nbytes = len; iov_iter_init(&iter, READ, &iov, 1, len); ret = filp->f_op->read_iter(&kiocb, &iter); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } EXPORT_SYMBOL(new_sync_read); |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 403 404 405 |
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 replace checking ... |
406 |
if (!(file->f_mode & FMODE_CAN_READ)) |
1da177e4c Linux-2.6.12-rc2 |
407 408 409 410 411 |
return -EINVAL; if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) return -EFAULT; ret = rw_verify_area(READ, file, pos, count); |
e28cc7157 Relax the rw_veri... |
412 413 |
if (ret >= 0) { count = ret; |
c43e259cc security: call se... |
414 415 |
if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); |
293bc9822 new methods: ->re... |
416 |
else if (file->f_op->aio_read) |
c43e259cc security: call se... |
417 |
ret = do_sync_read(file, buf, count, pos); |
293bc9822 new methods: ->re... |
418 419 |
else ret = new_sync_read(file, buf, count, pos); |
c43e259cc security: call se... |
420 |
if (ret > 0) { |
2a12a9d78 fsnotify: pass a ... |
421 |
fsnotify_access(file); |
c43e259cc security: call se... |
422 |
add_rchar(current, ret); |
1da177e4c Linux-2.6.12-rc2 |
423 |
} |
c43e259cc security: call se... |
424 |
inc_syscr(current); |
1da177e4c Linux-2.6.12-rc2 |
425 426 427 428 429 430 431 432 433 |
} return ret; } EXPORT_SYMBOL(vfs_read); ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { |
027445c37 [PATCH] Vectorize... |
434 |
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; |
1da177e4c Linux-2.6.12-rc2 |
435 436 437 438 439 |
struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; |
61964eba5 do_sync_read/writ... |
440 |
kiocb.ki_nbytes = len; |
027445c37 [PATCH] Vectorize... |
441 |
|
41003a7bc aio: remove retry... |
442 |
ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos); |
1da177e4c Linux-2.6.12-rc2 |
443 444 445 446 447 448 449 |
if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } EXPORT_SYMBOL(do_sync_write); |
293bc9822 new methods: ->re... |
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { 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); kiocb.ki_pos = *ppos; kiocb.ki_nbytes = len; iov_iter_init(&iter, WRITE, &iov, 1, len); ret = filp->f_op->write_iter(&kiocb, &iter); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } EXPORT_SYMBOL(new_sync_write); |
06ae43f34 Don't bother with... |
470 471 472 473 474 |
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) { mm_segment_t old_fs; const char __user *p; ssize_t ret; |
7f7f25e82 replace checking ... |
475 |
if (!(file->f_mode & FMODE_CAN_WRITE)) |
3e84f48ed vfs/splice: Fix m... |
476 |
return -EINVAL; |
06ae43f34 Don't bother with... |
477 478 479 480 481 482 483 |
old_fs = get_fs(); set_fs(get_ds()); p = (__force const char __user *)buf; if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; if (file->f_op->write) ret = file->f_op->write(file, p, count, pos); |
293bc9822 new methods: ->re... |
484 |
else if (file->f_op->aio_write) |
06ae43f34 Don't bother with... |
485 |
ret = do_sync_write(file, p, count, pos); |
293bc9822 new methods: ->re... |
486 487 |
else ret = new_sync_write(file, p, count, pos); |
06ae43f34 Don't bother with... |
488 489 490 491 492 493 494 495 |
set_fs(old_fs); if (ret > 0) { fsnotify_modify(file); add_wchar(current, ret); } inc_syscw(current); return ret; } |
2ec3a12a6 cachefiles_write_... |
496 |
EXPORT_SYMBOL(__kernel_write); |
1da177e4c Linux-2.6.12-rc2 |
497 498 499 500 501 502 |
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 replace checking ... |
503 |
if (!(file->f_mode & FMODE_CAN_WRITE)) |
1da177e4c Linux-2.6.12-rc2 |
504 505 506 507 508 |
return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; ret = rw_verify_area(WRITE, file, pos, count); |
e28cc7157 Relax the rw_veri... |
509 510 |
if (ret >= 0) { count = ret; |
03d95eb2f lift sb_start_wri... |
511 |
file_start_write(file); |
c43e259cc security: call se... |
512 513 |
if (file->f_op->write) ret = file->f_op->write(file, buf, count, pos); |
293bc9822 new methods: ->re... |
514 |
else if (file->f_op->aio_write) |
c43e259cc security: call se... |
515 |
ret = do_sync_write(file, buf, count, pos); |
293bc9822 new methods: ->re... |
516 517 |
else ret = new_sync_write(file, buf, count, pos); |
c43e259cc security: call se... |
518 |
if (ret > 0) { |
2a12a9d78 fsnotify: pass a ... |
519 |
fsnotify_modify(file); |
c43e259cc security: call se... |
520 |
add_wchar(current, ret); |
1da177e4c Linux-2.6.12-rc2 |
521 |
} |
c43e259cc security: call se... |
522 |
inc_syscw(current); |
03d95eb2f lift sb_start_wri... |
523 |
file_end_write(file); |
1da177e4c Linux-2.6.12-rc2 |
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
} return ret; } EXPORT_SYMBOL(vfs_write); static inline loff_t file_pos_read(struct file *file) { return file->f_pos; } static inline void file_pos_write(struct file *file, loff_t pos) { file->f_pos = pos; } |
3cdad4288 [CVE-2009-0029] S... |
540 |
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) |
1da177e4c Linux-2.6.12-rc2 |
541 |
{ |
9c225f265 vfs: atomic f_pos... |
542 |
struct fd f = fdget_pos(fd); |
1da177e4c Linux-2.6.12-rc2 |
543 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
544 |
|
2903ff019 switch simple cas... |
545 546 547 |
if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_read(f.file, buf, count, &pos); |
5faf153eb don't call file_p... |
548 549 |
if (ret >= 0) file_pos_write(f.file, pos); |
9c225f265 vfs: atomic f_pos... |
550 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
551 |
} |
1da177e4c Linux-2.6.12-rc2 |
552 553 |
return ret; } |
1da177e4c Linux-2.6.12-rc2 |
554 |
|
3cdad4288 [CVE-2009-0029] S... |
555 556 |
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count) |
1da177e4c Linux-2.6.12-rc2 |
557 |
{ |
9c225f265 vfs: atomic f_pos... |
558 |
struct fd f = fdget_pos(fd); |
1da177e4c Linux-2.6.12-rc2 |
559 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
560 |
|
2903ff019 switch simple cas... |
561 562 563 |
if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_write(f.file, buf, count, &pos); |
5faf153eb don't call file_p... |
564 565 |
if (ret >= 0) file_pos_write(f.file, pos); |
9c225f265 vfs: atomic f_pos... |
566 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
567 568 569 570 |
} return ret; } |
4a0fd5bf0 teach SYSCALL_DEF... |
571 572 |
SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf, size_t, count, loff_t, pos) |
1da177e4c Linux-2.6.12-rc2 |
573 |
{ |
2903ff019 switch simple cas... |
574 |
struct fd f; |
1da177e4c Linux-2.6.12-rc2 |
575 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
576 577 578 |
if (pos < 0) return -EINVAL; |
2903ff019 switch simple cas... |
579 580 |
f = fdget(fd); if (f.file) { |
1da177e4c Linux-2.6.12-rc2 |
581 |
ret = -ESPIPE; |
2903ff019 switch simple cas... |
582 583 584 |
if (f.file->f_mode & FMODE_PREAD) ret = vfs_read(f.file, buf, count, &pos); fdput(f); |
1da177e4c Linux-2.6.12-rc2 |
585 586 587 588 |
} return ret; } |
4a0fd5bf0 teach SYSCALL_DEF... |
589 590 |
SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf, size_t, count, loff_t, pos) |
1da177e4c Linux-2.6.12-rc2 |
591 |
{ |
2903ff019 switch simple cas... |
592 |
struct fd f; |
1da177e4c Linux-2.6.12-rc2 |
593 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
594 595 596 |
if (pos < 0) return -EINVAL; |
2903ff019 switch simple cas... |
597 598 |
f = fdget(fd); if (f.file) { |
1da177e4c Linux-2.6.12-rc2 |
599 |
ret = -ESPIPE; |
2903ff019 switch simple cas... |
600 601 602 |
if (f.file->f_mode & FMODE_PWRITE) ret = vfs_write(f.file, buf, count, &pos); fdput(f); |
1da177e4c Linux-2.6.12-rc2 |
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
} return ret; } /* * Reduce an iovec's length in-place. Return the resulting number of segments */ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) { unsigned long seg = 0; size_t len = 0; while (seg < nr_segs) { seg++; if (len + iov->iov_len >= to) { iov->iov_len = to - len; break; } len += iov->iov_len; iov++; } return seg; } |
19295529d ext4: export iov_... |
627 |
EXPORT_SYMBOL(iov_shorten); |
1da177e4c Linux-2.6.12-rc2 |
628 |
|
293bc9822 new methods: ->re... |
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
static ssize_t do_iter_readv_writev(struct file *filp, int rw, const struct iovec *iov, unsigned long nr_segs, size_t len, loff_t *ppos, iter_fn_t fn) { struct kiocb kiocb; struct iov_iter iter; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_nbytes = len; iov_iter_init(&iter, rw, iov, nr_segs, len); ret = fn(&kiocb, &iter); if (ret == -EIOCBQUEUED) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } |
72ec35163 switch compat rea... |
647 |
static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, |
ee0b3e671 [PATCH] Remove re... |
648 649 650 651 652 653 654 |
unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) { struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; |
ee0b3e671 [PATCH] Remove re... |
655 |
kiocb.ki_nbytes = len; |
41003a7bc aio: remove retry... |
656 |
ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos); |
ee0b3e671 [PATCH] Remove re... |
657 658 659 660 661 662 663 |
if (ret == -EIOCBQUEUED) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; } /* Do it by hand, with file-ops */ |
72ec35163 switch compat rea... |
664 |
static ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, |
ee0b3e671 [PATCH] Remove re... |
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
unsigned long nr_segs, loff_t *ppos, io_fn_t fn) { struct iovec *vector = iov; ssize_t ret = 0; while (nr_segs > 0) { void __user *base; size_t len; ssize_t nr; base = vector->iov_base; len = vector->iov_len; vector++; nr_segs--; nr = fn(filp, base, len, ppos); if (nr < 0) { if (!ret) ret = nr; break; } ret += nr; if (nr != len) break; } return ret; } |
1da177e4c Linux-2.6.12-rc2 |
694 695 |
/* A write operation does a read from user space and vice versa */ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) |
eed4e51fb [PATCH] Add vecto... |
696 697 698 |
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, |
ac34ebb3a aio/vfs: cleanup ... |
699 |
struct iovec **ret_pointer) |
435f49a51 readv/writev: do ... |
700 |
{ |
eed4e51fb [PATCH] Add vecto... |
701 |
unsigned long seg; |
435f49a51 readv/writev: do ... |
702 |
ssize_t ret; |
eed4e51fb [PATCH] Add vecto... |
703 |
struct iovec *iov = fast_pointer; |
435f49a51 readv/writev: do ... |
704 705 706 707 708 |
/* * SuS says "The readv() function *may* fail if the iovcnt argument * was less than or equal to 0, or greater than {IOV_MAX}. Linux has * traditionally returned zero for zero segments, so... */ |
eed4e51fb [PATCH] Add vecto... |
709 710 |
if (nr_segs == 0) { ret = 0; |
435f49a51 readv/writev: do ... |
711 |
goto out; |
eed4e51fb [PATCH] Add vecto... |
712 |
} |
435f49a51 readv/writev: do ... |
713 714 715 716 |
/* * First get the "struct iovec" from user memory and * verify all the pointers */ |
eed4e51fb [PATCH] Add vecto... |
717 718 |
if (nr_segs > UIO_MAXIOV) { ret = -EINVAL; |
435f49a51 readv/writev: do ... |
719 |
goto out; |
eed4e51fb [PATCH] Add vecto... |
720 721 |
} if (nr_segs > fast_segs) { |
435f49a51 readv/writev: do ... |
722 |
iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); |
eed4e51fb [PATCH] Add vecto... |
723 724 |
if (iov == NULL) { ret = -ENOMEM; |
435f49a51 readv/writev: do ... |
725 |
goto out; |
eed4e51fb [PATCH] Add vecto... |
726 |
} |
435f49a51 readv/writev: do ... |
727 |
} |
eed4e51fb [PATCH] Add vecto... |
728 729 |
if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { ret = -EFAULT; |
435f49a51 readv/writev: do ... |
730 |
goto out; |
eed4e51fb [PATCH] Add vecto... |
731 |
} |
435f49a51 readv/writev: do ... |
732 |
/* |
eed4e51fb [PATCH] Add vecto... |
733 734 735 736 |
* According to the Single Unix Specification we should return EINVAL * if an element length is < 0 when cast to ssize_t or if the * total length would overflow the ssize_t return value of the * system call. |
435f49a51 readv/writev: do ... |
737 738 739 740 |
* * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the * overflow case. */ |
eed4e51fb [PATCH] Add vecto... |
741 |
ret = 0; |
435f49a51 readv/writev: do ... |
742 743 744 |
for (seg = 0; seg < nr_segs; seg++) { void __user *buf = iov[seg].iov_base; ssize_t len = (ssize_t)iov[seg].iov_len; |
eed4e51fb [PATCH] Add vecto... |
745 746 747 |
/* see if we we're about to use an invalid len or if * it's about to overflow ssize_t */ |
435f49a51 readv/writev: do ... |
748 |
if (len < 0) { |
eed4e51fb [PATCH] Add vecto... |
749 |
ret = -EINVAL; |
435f49a51 readv/writev: do ... |
750 |
goto out; |
eed4e51fb [PATCH] Add vecto... |
751 |
} |
ac34ebb3a aio/vfs: cleanup ... |
752 |
if (type >= 0 |
fcf634098 Cross Memory Attach |
753 |
&& unlikely(!access_ok(vrfy_dir(type), buf, len))) { |
eed4e51fb [PATCH] Add vecto... |
754 |
ret = -EFAULT; |
435f49a51 readv/writev: do ... |
755 756 757 758 759 |
goto out; } if (len > MAX_RW_COUNT - ret) { len = MAX_RW_COUNT - ret; iov[seg].iov_len = len; |
eed4e51fb [PATCH] Add vecto... |
760 |
} |
eed4e51fb [PATCH] Add vecto... |
761 |
ret += len; |
435f49a51 readv/writev: do ... |
762 |
} |
eed4e51fb [PATCH] Add vecto... |
763 764 765 766 |
out: *ret_pointer = iov; return ret; } |
1da177e4c Linux-2.6.12-rc2 |
767 768 769 770 |
static ssize_t do_readv_writev(int type, struct file *file, const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) { |
1da177e4c Linux-2.6.12-rc2 |
771 772 |
size_t tot_len; struct iovec iovstack[UIO_FASTIOV]; |
ee0b3e671 [PATCH] Remove re... |
773 |
struct iovec *iov = iovstack; |
1da177e4c Linux-2.6.12-rc2 |
774 |
ssize_t ret; |
1da177e4c Linux-2.6.12-rc2 |
775 776 |
io_fn_t fn; iov_fn_t fnv; |
293bc9822 new methods: ->re... |
777 |
iter_fn_t iter_fn; |
1da177e4c Linux-2.6.12-rc2 |
778 |
|
eed4e51fb [PATCH] Add vecto... |
779 |
ret = rw_copy_check_uvector(type, uvector, nr_segs, |
ac34ebb3a aio/vfs: cleanup ... |
780 |
ARRAY_SIZE(iovstack), iovstack, &iov); |
eed4e51fb [PATCH] Add vecto... |
781 |
if (ret <= 0) |
1da177e4c Linux-2.6.12-rc2 |
782 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
783 |
|
eed4e51fb [PATCH] Add vecto... |
784 |
tot_len = ret; |
1da177e4c Linux-2.6.12-rc2 |
785 |
ret = rw_verify_area(type, file, pos, tot_len); |
e28cc7157 Relax the rw_veri... |
786 |
if (ret < 0) |
1da177e4c Linux-2.6.12-rc2 |
787 788 789 790 791 |
goto out; fnv = NULL; if (type == READ) { fn = file->f_op->read; |
ee0b3e671 [PATCH] Remove re... |
792 |
fnv = file->f_op->aio_read; |
293bc9822 new methods: ->re... |
793 |
iter_fn = file->f_op->read_iter; |
1da177e4c Linux-2.6.12-rc2 |
794 795 |
} else { fn = (io_fn_t)file->f_op->write; |
ee0b3e671 [PATCH] Remove re... |
796 |
fnv = file->f_op->aio_write; |
293bc9822 new methods: ->re... |
797 |
iter_fn = file->f_op->write_iter; |
03d95eb2f lift sb_start_wri... |
798 |
file_start_write(file); |
1da177e4c Linux-2.6.12-rc2 |
799 |
} |
293bc9822 new methods: ->re... |
800 801 802 803 |
if (iter_fn) ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len, pos, iter_fn); else if (fnv) |
ee0b3e671 [PATCH] Remove re... |
804 805 806 807 |
ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, pos, fnv); else ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); |
1da177e4c Linux-2.6.12-rc2 |
808 |
|
03d95eb2f lift sb_start_wri... |
809 810 |
if (type != READ) file_end_write(file); |
1da177e4c Linux-2.6.12-rc2 |
811 812 813 |
out: if (iov != iovstack) kfree(iov); |
0eeca2830 [PATCH] inotify |
814 815 |
if ((ret + (type == READ)) > 0) { if (type == READ) |
2a12a9d78 fsnotify: pass a ... |
816 |
fsnotify_access(file); |
0eeca2830 [PATCH] inotify |
817 |
else |
2a12a9d78 fsnotify: pass a ... |
818 |
fsnotify_modify(file); |
0eeca2830 [PATCH] inotify |
819 |
} |
1da177e4c Linux-2.6.12-rc2 |
820 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
821 822 823 824 825 826 827 |
} ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, unsigned long vlen, loff_t *pos) { if (!(file->f_mode & FMODE_READ)) return -EBADF; |
7f7f25e82 replace checking ... |
828 |
if (!(file->f_mode & FMODE_CAN_READ)) |
1da177e4c Linux-2.6.12-rc2 |
829 830 831 832 833 834 835 836 837 838 839 840 |
return -EINVAL; return do_readv_writev(READ, file, vec, vlen, pos); } EXPORT_SYMBOL(vfs_readv); ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, unsigned long vlen, loff_t *pos) { if (!(file->f_mode & FMODE_WRITE)) return -EBADF; |
7f7f25e82 replace checking ... |
841 |
if (!(file->f_mode & FMODE_CAN_WRITE)) |
1da177e4c Linux-2.6.12-rc2 |
842 843 844 845 846 847 |
return -EINVAL; return do_readv_writev(WRITE, file, vec, vlen, pos); } EXPORT_SYMBOL(vfs_writev); |
3cdad4288 [CVE-2009-0029] S... |
848 849 |
SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen) |
1da177e4c Linux-2.6.12-rc2 |
850 |
{ |
9c225f265 vfs: atomic f_pos... |
851 |
struct fd f = fdget_pos(fd); |
1da177e4c Linux-2.6.12-rc2 |
852 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
853 |
|
2903ff019 switch simple cas... |
854 855 856 |
if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_readv(f.file, vec, vlen, &pos); |
5faf153eb don't call file_p... |
857 858 |
if (ret >= 0) file_pos_write(f.file, pos); |
9c225f265 vfs: atomic f_pos... |
859 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
860 861 862 |
} if (ret > 0) |
4b98d11b4 [PATCH] ifdef ->r... |
863 864 |
add_rchar(current, ret); inc_syscr(current); |
1da177e4c Linux-2.6.12-rc2 |
865 866 |
return ret; } |
3cdad4288 [CVE-2009-0029] S... |
867 868 |
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen) |
1da177e4c Linux-2.6.12-rc2 |
869 |
{ |
9c225f265 vfs: atomic f_pos... |
870 |
struct fd f = fdget_pos(fd); |
1da177e4c Linux-2.6.12-rc2 |
871 |
ssize_t ret = -EBADF; |
1da177e4c Linux-2.6.12-rc2 |
872 |
|
2903ff019 switch simple cas... |
873 874 875 |
if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_writev(f.file, vec, vlen, &pos); |
5faf153eb don't call file_p... |
876 877 |
if (ret >= 0) file_pos_write(f.file, pos); |
9c225f265 vfs: atomic f_pos... |
878 |
fdput_pos(f); |
1da177e4c Linux-2.6.12-rc2 |
879 880 881 |
} if (ret > 0) |
4b98d11b4 [PATCH] ifdef ->r... |
882 883 |
add_wchar(current, ret); inc_syscw(current); |
1da177e4c Linux-2.6.12-rc2 |
884 885 |
return ret; } |
601cc11d0 Make non-compat p... |
886 887 888 889 890 |
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; } |
f3554f4bc preadv/pwritev: A... |
891 |
SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec, |
601cc11d0 Make non-compat p... |
892 |
unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) |
f3554f4bc preadv/pwritev: A... |
893 |
{ |
601cc11d0 Make non-compat p... |
894 |
loff_t pos = pos_from_hilo(pos_h, pos_l); |
2903ff019 switch simple cas... |
895 |
struct fd f; |
f3554f4bc preadv/pwritev: A... |
896 |
ssize_t ret = -EBADF; |
f3554f4bc preadv/pwritev: A... |
897 898 899 |
if (pos < 0) return -EINVAL; |
2903ff019 switch simple cas... |
900 901 |
f = fdget(fd); if (f.file) { |
f3554f4bc preadv/pwritev: A... |
902 |
ret = -ESPIPE; |
2903ff019 switch simple cas... |
903 904 905 |
if (f.file->f_mode & FMODE_PREAD) ret = vfs_readv(f.file, vec, vlen, &pos); fdput(f); |
f3554f4bc preadv/pwritev: A... |
906 907 908 909 910 911 912 913 914 |
} if (ret > 0) add_rchar(current, ret); inc_syscr(current); return ret; } SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec, |
601cc11d0 Make non-compat p... |
915 |
unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) |
f3554f4bc preadv/pwritev: A... |
916 |
{ |
601cc11d0 Make non-compat p... |
917 |
loff_t pos = pos_from_hilo(pos_h, pos_l); |
2903ff019 switch simple cas... |
918 |
struct fd f; |
f3554f4bc preadv/pwritev: A... |
919 |
ssize_t ret = -EBADF; |
f3554f4bc preadv/pwritev: A... |
920 921 922 |
if (pos < 0) return -EINVAL; |
2903ff019 switch simple cas... |
923 924 |
f = fdget(fd); if (f.file) { |
f3554f4bc preadv/pwritev: A... |
925 |
ret = -ESPIPE; |
2903ff019 switch simple cas... |
926 927 928 |
if (f.file->f_mode & FMODE_PWRITE) ret = vfs_writev(f.file, vec, vlen, &pos); fdput(f); |
f3554f4bc preadv/pwritev: A... |
929 930 931 932 933 934 935 |
} if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; } |
72ec35163 switch compat rea... |
936 937 938 939 940 941 942 943 944 945 946 947 |
#ifdef CONFIG_COMPAT static ssize_t compat_do_readv_writev(int type, struct file *file, const struct compat_iovec __user *uvector, unsigned long nr_segs, loff_t *pos) { compat_ssize_t tot_len; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; ssize_t ret; io_fn_t fn; iov_fn_t fnv; |
293bc9822 new methods: ->re... |
948 |
iter_fn_t iter_fn; |
72ec35163 switch compat rea... |
949 |
|
72ec35163 switch compat rea... |
950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
ret = compat_rw_copy_check_uvector(type, uvector, nr_segs, UIO_FASTIOV, iovstack, &iov); if (ret <= 0) goto out; tot_len = ret; ret = rw_verify_area(type, file, pos, tot_len); if (ret < 0) goto out; fnv = NULL; if (type == READ) { fn = file->f_op->read; fnv = file->f_op->aio_read; |
293bc9822 new methods: ->re... |
964 |
iter_fn = file->f_op->read_iter; |
72ec35163 switch compat rea... |
965 966 967 |
} else { fn = (io_fn_t)file->f_op->write; fnv = file->f_op->aio_write; |
293bc9822 new methods: ->re... |
968 |
iter_fn = file->f_op->write_iter; |
03d95eb2f lift sb_start_wri... |
969 |
file_start_write(file); |
72ec35163 switch compat rea... |
970 |
} |
293bc9822 new methods: ->re... |
971 972 973 974 |
if (iter_fn) ret = do_iter_readv_writev(file, type, iov, nr_segs, tot_len, pos, iter_fn); else if (fnv) |
72ec35163 switch compat rea... |
975 976 |
ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, pos, fnv); |
03d95eb2f lift sb_start_wri... |
977 |
else |
72ec35163 switch compat rea... |
978 |
ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); |
03d95eb2f lift sb_start_wri... |
979 980 |
if (type != READ) file_end_write(file); |
72ec35163 switch compat rea... |
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
out: if (iov != iovstack) kfree(iov); if ((ret + (type == READ)) > 0) { if (type == READ) fsnotify_access(file); else fsnotify_modify(file); } return ret; } static size_t compat_readv(struct file *file, const struct compat_iovec __user *vec, unsigned long vlen, loff_t *pos) { ssize_t ret = -EBADF; if (!(file->f_mode & FMODE_READ)) goto out; ret = -EINVAL; |
7f7f25e82 replace checking ... |
1003 |
if (!(file->f_mode & FMODE_CAN_READ)) |
72ec35163 switch compat rea... |
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
goto out; ret = compat_do_readv_writev(READ, file, vec, vlen, pos); out: if (ret > 0) add_rchar(current, ret); inc_syscr(current); return ret; } |
dfd948e32 fs/compat: fix pa... |
1014 |
COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, |
72ec35163 switch compat rea... |
1015 |
const struct compat_iovec __user *,vec, |
dfd948e32 fs/compat: fix pa... |
1016 |
compat_ulong_t, vlen) |
72ec35163 switch compat rea... |
1017 |
{ |
9c225f265 vfs: atomic f_pos... |
1018 |
struct fd f = fdget_pos(fd); |
72ec35163 switch compat rea... |
1019 1020 1021 1022 1023 1024 1025 |
ssize_t ret; loff_t pos; if (!f.file) return -EBADF; pos = f.file->f_pos; ret = compat_readv(f.file, vec, vlen, &pos); |
5faf153eb don't call file_p... |
1026 1027 |
if (ret >= 0) f.file->f_pos = pos; |
9c225f265 vfs: atomic f_pos... |
1028 |
fdput_pos(f); |
72ec35163 switch compat rea... |
1029 1030 |
return ret; } |
378a10f3a fs/compat: option... |
1031 1032 1033 |
static long __compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen, loff_t pos) |
72ec35163 switch compat rea... |
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
{ struct fd f; ssize_t ret; if (pos < 0) return -EINVAL; f = fdget(fd); if (!f.file) return -EBADF; ret = -ESPIPE; if (f.file->f_mode & FMODE_PREAD) ret = compat_readv(f.file, vec, vlen, &pos); fdput(f); return ret; } |
378a10f3a fs/compat: option... |
1049 1050 1051 1052 1053 1054 1055 1056 |
#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64 COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, const struct compat_iovec __user *,vec, unsigned long, vlen, loff_t, pos) { return __compat_sys_preadv64(fd, vec, vlen, pos); } #endif |
dfd948e32 fs/compat: fix pa... |
1057 |
COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, |
72ec35163 switch compat rea... |
1058 |
const struct compat_iovec __user *,vec, |
dfd948e32 fs/compat: fix pa... |
1059 |
compat_ulong_t, vlen, u32, pos_low, u32, pos_high) |
72ec35163 switch compat rea... |
1060 1061 |
{ loff_t pos = ((loff_t)pos_high << 32) | pos_low; |
378a10f3a fs/compat: option... |
1062 1063 |
return __compat_sys_preadv64(fd, vec, vlen, pos); |
72ec35163 switch compat rea... |
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
} static size_t compat_writev(struct file *file, const struct compat_iovec __user *vec, unsigned long vlen, loff_t *pos) { ssize_t ret = -EBADF; if (!(file->f_mode & FMODE_WRITE)) goto out; ret = -EINVAL; |
7f7f25e82 replace checking ... |
1076 |
if (!(file->f_mode & FMODE_CAN_WRITE)) |
72ec35163 switch compat rea... |
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
goto out; ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); out: if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; } |
dfd948e32 fs/compat: fix pa... |
1087 |
COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, |
72ec35163 switch compat rea... |
1088 |
const struct compat_iovec __user *, vec, |
dfd948e32 fs/compat: fix pa... |
1089 |
compat_ulong_t, vlen) |
72ec35163 switch compat rea... |
1090 |
{ |
9c225f265 vfs: atomic f_pos... |
1091 |
struct fd f = fdget_pos(fd); |
72ec35163 switch compat rea... |
1092 1093 1094 1095 1096 1097 1098 |
ssize_t ret; loff_t pos; if (!f.file) return -EBADF; pos = f.file->f_pos; ret = compat_writev(f.file, vec, vlen, &pos); |
5faf153eb don't call file_p... |
1099 1100 |
if (ret >= 0) f.file->f_pos = pos; |
9c225f265 vfs: atomic f_pos... |
1101 |
fdput_pos(f); |
72ec35163 switch compat rea... |
1102 1103 |
return ret; } |
378a10f3a fs/compat: option... |
1104 1105 1106 |
static long __compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen, loff_t pos) |
72ec35163 switch compat rea... |
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 |
{ struct fd f; ssize_t ret; if (pos < 0) return -EINVAL; f = fdget(fd); if (!f.file) return -EBADF; ret = -ESPIPE; if (f.file->f_mode & FMODE_PWRITE) ret = compat_writev(f.file, vec, vlen, &pos); fdput(f); return ret; } |
378a10f3a fs/compat: option... |
1122 1123 1124 1125 1126 1127 1128 1129 |
#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64 COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, const struct compat_iovec __user *,vec, unsigned long, vlen, loff_t, pos) { return __compat_sys_pwritev64(fd, vec, vlen, pos); } #endif |
dfd948e32 fs/compat: fix pa... |
1130 |
COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, |
72ec35163 switch compat rea... |
1131 |
const struct compat_iovec __user *,vec, |
dfd948e32 fs/compat: fix pa... |
1132 |
compat_ulong_t, vlen, u32, pos_low, u32, pos_high) |
72ec35163 switch compat rea... |
1133 1134 |
{ loff_t pos = ((loff_t)pos_high << 32) | pos_low; |
378a10f3a fs/compat: option... |
1135 1136 |
return __compat_sys_pwritev64(fd, vec, vlen, pos); |
72ec35163 switch compat rea... |
1137 1138 |
} #endif |
19f4fc3ae convert sendfile{... |
1139 1140 |
static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, loff_t max) |
1da177e4c Linux-2.6.12-rc2 |
1141 |
{ |
2903ff019 switch simple cas... |
1142 1143 |
struct fd in, out; struct inode *in_inode, *out_inode; |
1da177e4c Linux-2.6.12-rc2 |
1144 |
loff_t pos; |
7995bd287 splice: don't pas... |
1145 |
loff_t out_pos; |
1da177e4c Linux-2.6.12-rc2 |
1146 |
ssize_t retval; |
2903ff019 switch simple cas... |
1147 |
int fl; |
1da177e4c Linux-2.6.12-rc2 |
1148 1149 1150 1151 1152 |
/* * Get input file, and verify that it is ok.. */ retval = -EBADF; |
2903ff019 switch simple cas... |
1153 1154 |
in = fdget(in_fd); if (!in.file) |
1da177e4c Linux-2.6.12-rc2 |
1155 |
goto out; |
2903ff019 switch simple cas... |
1156 |
if (!(in.file->f_mode & FMODE_READ)) |
1da177e4c Linux-2.6.12-rc2 |
1157 |
goto fput_in; |
1da177e4c Linux-2.6.12-rc2 |
1158 |
retval = -ESPIPE; |
7995bd287 splice: don't pas... |
1159 1160 1161 1162 |
if (!ppos) { pos = in.file->f_pos; } else { pos = *ppos; |
2903ff019 switch simple cas... |
1163 |
if (!(in.file->f_mode & FMODE_PREAD)) |
1da177e4c Linux-2.6.12-rc2 |
1164 |
goto fput_in; |
7995bd287 splice: don't pas... |
1165 1166 |
} retval = rw_verify_area(READ, in.file, &pos, count); |
e28cc7157 Relax the rw_veri... |
1167 |
if (retval < 0) |
1da177e4c Linux-2.6.12-rc2 |
1168 |
goto fput_in; |
e28cc7157 Relax the rw_veri... |
1169 |
count = retval; |
1da177e4c Linux-2.6.12-rc2 |
1170 |
|
1da177e4c Linux-2.6.12-rc2 |
1171 1172 1173 1174 |
/* * Get output file, and verify that it is ok.. */ retval = -EBADF; |
2903ff019 switch simple cas... |
1175 1176 |
out = fdget(out_fd); if (!out.file) |
1da177e4c Linux-2.6.12-rc2 |
1177 |
goto fput_in; |
2903ff019 switch simple cas... |
1178 |
if (!(out.file->f_mode & FMODE_WRITE)) |
1da177e4c Linux-2.6.12-rc2 |
1179 1180 |
goto fput_out; retval = -EINVAL; |
496ad9aa8 new helper: file_... |
1181 1182 |
in_inode = file_inode(in.file); out_inode = file_inode(out.file); |
7995bd287 splice: don't pas... |
1183 1184 |
out_pos = out.file->f_pos; retval = rw_verify_area(WRITE, out.file, &out_pos, count); |
e28cc7157 Relax the rw_veri... |
1185 |
if (retval < 0) |
1da177e4c Linux-2.6.12-rc2 |
1186 |
goto fput_out; |
e28cc7157 Relax the rw_veri... |
1187 |
count = retval; |
1da177e4c Linux-2.6.12-rc2 |
1188 |
|
1da177e4c Linux-2.6.12-rc2 |
1189 1190 |
if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); |
1da177e4c Linux-2.6.12-rc2 |
1191 1192 1193 1194 1195 1196 |
if (unlikely(pos + count > max)) { retval = -EOVERFLOW; if (pos >= max) goto fput_out; count = max - pos; } |
d96e6e716 Remove remnants o... |
1197 |
fl = 0; |
534f2aaa6 sys_sendfile: swi... |
1198 |
#if 0 |
d96e6e716 Remove remnants o... |
1199 1200 1201 1202 1203 1204 |
/* * 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 switch simple cas... |
1205 |
if (in.file->f_flags & O_NONBLOCK) |
d96e6e716 Remove remnants o... |
1206 |
fl = SPLICE_F_NONBLOCK; |
534f2aaa6 sys_sendfile: swi... |
1207 |
#endif |
50cd2c577 lift file_*_write... |
1208 |
file_start_write(out.file); |
7995bd287 splice: don't pas... |
1209 |
retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); |
50cd2c577 lift file_*_write... |
1210 |
file_end_write(out.file); |
1da177e4c Linux-2.6.12-rc2 |
1211 1212 |
if (retval > 0) { |
4b98d11b4 [PATCH] ifdef ->r... |
1213 1214 |
add_rchar(current, retval); add_wchar(current, retval); |
a68c2f12b sendfile: allows ... |
1215 1216 |
fsnotify_access(in.file); fsnotify_modify(out.file); |
7995bd287 splice: don't pas... |
1217 1218 1219 1220 1221 |
out.file->f_pos = out_pos; if (ppos) *ppos = pos; else in.file->f_pos = pos; |
1da177e4c Linux-2.6.12-rc2 |
1222 |
} |
1da177e4c Linux-2.6.12-rc2 |
1223 |
|
4b98d11b4 [PATCH] ifdef ->r... |
1224 1225 |
inc_syscr(current); inc_syscw(current); |
7995bd287 splice: don't pas... |
1226 |
if (pos > max) |
1da177e4c Linux-2.6.12-rc2 |
1227 1228 1229 |
retval = -EOVERFLOW; fput_out: |
2903ff019 switch simple cas... |
1230 |
fdput(out); |
1da177e4c Linux-2.6.12-rc2 |
1231 |
fput_in: |
2903ff019 switch simple cas... |
1232 |
fdput(in); |
1da177e4c Linux-2.6.12-rc2 |
1233 1234 1235 |
out: return retval; } |
002c8976e [CVE-2009-0029] S... |
1236 |
SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) |
1da177e4c Linux-2.6.12-rc2 |
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
{ 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 [CVE-2009-0029] S... |
1254 |
SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count) |
1da177e4c Linux-2.6.12-rc2 |
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
{ 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 convert sendfile{... |
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 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 |
#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 |