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