]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/read_write.c
[PATCH] Remove readv/writev methods and use aio_read/aio_write instead
[net-next-2.6.git] / fs / read_write.c
CommitLineData
1da177e4
LT
1/*
2 * linux/fs/read_write.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7#include <linux/slab.h>
8#include <linux/stat.h>
9#include <linux/fcntl.h>
10#include <linux/file.h>
11#include <linux/uio.h>
12#include <linux/smp_lock.h>
0eeca283 13#include <linux/fsnotify.h>
1da177e4
LT
14#include <linux/security.h>
15#include <linux/module.h>
16#include <linux/syscalls.h>
e28cc715 17#include <linux/pagemap.h>
ee0b3e67 18#include "read_write.h"
1da177e4
LT
19
20#include <asm/uaccess.h>
21#include <asm/unistd.h>
22
4b6f5d20 23const struct file_operations generic_ro_fops = {
1da177e4
LT
24 .llseek = generic_file_llseek,
25 .read = generic_file_read,
26 .mmap = generic_file_readonly_mmap,
27 .sendfile = generic_file_sendfile,
28};
29
30EXPORT_SYMBOL(generic_ro_fops);
31
32loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
33{
34 long long retval;
35 struct inode *inode = file->f_mapping->host;
36
1b1dcc1b 37 mutex_lock(&inode->i_mutex);
1da177e4
LT
38 switch (origin) {
39 case 2:
40 offset += inode->i_size;
41 break;
42 case 1:
43 offset += file->f_pos;
44 }
45 retval = -EINVAL;
46 if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
47 if (offset != file->f_pos) {
48 file->f_pos = offset;
49 file->f_version = 0;
50 }
51 retval = offset;
52 }
1b1dcc1b 53 mutex_unlock(&inode->i_mutex);
1da177e4
LT
54 return retval;
55}
56
57EXPORT_SYMBOL(generic_file_llseek);
58
59loff_t remote_llseek(struct file *file, loff_t offset, int origin)
60{
61 long long retval;
62
63 lock_kernel();
64 switch (origin) {
65 case 2:
66 offset += i_size_read(file->f_dentry->d_inode);
67 break;
68 case 1:
69 offset += file->f_pos;
70 }
71 retval = -EINVAL;
72 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
73 if (offset != file->f_pos) {
74 file->f_pos = offset;
75 file->f_version = 0;
76 }
77 retval = offset;
78 }
79 unlock_kernel();
80 return retval;
81}
82EXPORT_SYMBOL(remote_llseek);
83
84loff_t no_llseek(struct file *file, loff_t offset, int origin)
85{
86 return -ESPIPE;
87}
88EXPORT_SYMBOL(no_llseek);
89
90loff_t default_llseek(struct file *file, loff_t offset, int origin)
91{
92 long long retval;
93
94 lock_kernel();
95 switch (origin) {
96 case 2:
97 offset += i_size_read(file->f_dentry->d_inode);
98 break;
99 case 1:
100 offset += file->f_pos;
101 }
102 retval = -EINVAL;
103 if (offset >= 0) {
104 if (offset != file->f_pos) {
105 file->f_pos = offset;
106 file->f_version = 0;
107 }
108 retval = offset;
109 }
110 unlock_kernel();
111 return retval;
112}
113EXPORT_SYMBOL(default_llseek);
114
115loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
116{
117 loff_t (*fn)(struct file *, loff_t, int);
118
119 fn = no_llseek;
120 if (file->f_mode & FMODE_LSEEK) {
121 fn = default_llseek;
122 if (file->f_op && file->f_op->llseek)
123 fn = file->f_op->llseek;
124 }
125 return fn(file, offset, origin);
126}
127EXPORT_SYMBOL(vfs_llseek);
128
129asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
130{
131 off_t retval;
132 struct file * file;
133 int fput_needed;
134
135 retval = -EBADF;
136 file = fget_light(fd, &fput_needed);
137 if (!file)
138 goto bad;
139
140 retval = -EINVAL;
141 if (origin <= 2) {
142 loff_t res = vfs_llseek(file, offset, origin);
143 retval = res;
144 if (res != (loff_t)retval)
145 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
146 }
147 fput_light(file, fput_needed);
148bad:
149 return retval;
150}
151
152#ifdef __ARCH_WANT_SYS_LLSEEK
153asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
154 unsigned long offset_low, loff_t __user * result,
155 unsigned int origin)
156{
157 int retval;
158 struct file * file;
159 loff_t offset;
160 int fput_needed;
161
162 retval = -EBADF;
163 file = fget_light(fd, &fput_needed);
164 if (!file)
165 goto bad;
166
167 retval = -EINVAL;
168 if (origin > 2)
169 goto out_putf;
170
171 offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
172 origin);
173
174 retval = (int)offset;
175 if (offset >= 0) {
176 retval = -EFAULT;
177 if (!copy_to_user(result, &offset, sizeof(offset)))
178 retval = 0;
179 }
180out_putf:
181 fput_light(file, fput_needed);
182bad:
183 return retval;
184}
185#endif
186
e28cc715
LT
187/*
188 * rw_verify_area doesn't like huge counts. We limit
189 * them to something that fits in "int" so that others
190 * won't have to do range checks all the time.
191 */
192#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
1da177e4
LT
193
194int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
195{
196 struct inode *inode;
197 loff_t pos;
198
e28cc715 199 if (unlikely((ssize_t) count < 0))
1da177e4
LT
200 goto Einval;
201 pos = *ppos;
202 if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
203 goto Einval;
204
205 inode = file->f_dentry->d_inode;
49570e9b 206 if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
e28cc715
LT
207 int retval = locks_mandatory_area(
208 read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
209 inode, file, pos, count);
210 if (retval < 0)
211 return retval;
212 }
213 return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
1da177e4
LT
214
215Einval:
216 return -EINVAL;
217}
218
63e68809
BL
219static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
220{
221 set_current_state(TASK_UNINTERRUPTIBLE);
222 if (!kiocbIsKicked(iocb))
223 schedule();
224 else
225 kiocbClearKicked(iocb);
226 __set_current_state(TASK_RUNNING);
227}
228
1da177e4
LT
229ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
230{
027445c3 231 struct iovec iov = { .iov_base = buf, .iov_len = len };
1da177e4
LT
232 struct kiocb kiocb;
233 ssize_t ret;
234
235 init_sync_kiocb(&kiocb, filp);
236 kiocb.ki_pos = *ppos;
027445c3
BP
237 kiocb.ki_left = len;
238
239 for (;;) {
240 ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
241 if (ret != -EIOCBRETRY)
242 break;
63e68809 243 wait_on_retry_sync_kiocb(&kiocb);
027445c3 244 }
63e68809 245
1da177e4
LT
246 if (-EIOCBQUEUED == ret)
247 ret = wait_on_sync_kiocb(&kiocb);
248 *ppos = kiocb.ki_pos;
249 return ret;
250}
251
252EXPORT_SYMBOL(do_sync_read);
253
254ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
255{
256 ssize_t ret;
257
258 if (!(file->f_mode & FMODE_READ))
259 return -EBADF;
260 if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
261 return -EINVAL;
262 if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
263 return -EFAULT;
264
265 ret = rw_verify_area(READ, file, pos, count);
e28cc715
LT
266 if (ret >= 0) {
267 count = ret;
1da177e4
LT
268 ret = security_file_permission (file, MAY_READ);
269 if (!ret) {
270 if (file->f_op->read)
271 ret = file->f_op->read(file, buf, count, pos);
272 else
273 ret = do_sync_read(file, buf, count, pos);
274 if (ret > 0) {
0eeca283 275 fsnotify_access(file->f_dentry);
1da177e4
LT
276 current->rchar += ret;
277 }
278 current->syscr++;
279 }
280 }
281
282 return ret;
283}
284
285EXPORT_SYMBOL(vfs_read);
286
287ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
288{
027445c3 289 struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
1da177e4
LT
290 struct kiocb kiocb;
291 ssize_t ret;
292
293 init_sync_kiocb(&kiocb, filp);
294 kiocb.ki_pos = *ppos;
027445c3
BP
295 kiocb.ki_left = len;
296
297 for (;;) {
298 ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
299 if (ret != -EIOCBRETRY)
300 break;
63e68809 301 wait_on_retry_sync_kiocb(&kiocb);
027445c3 302 }
63e68809 303
1da177e4
LT
304 if (-EIOCBQUEUED == ret)
305 ret = wait_on_sync_kiocb(&kiocb);
306 *ppos = kiocb.ki_pos;
307 return ret;
308}
309
310EXPORT_SYMBOL(do_sync_write);
311
312ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
313{
314 ssize_t ret;
315
316 if (!(file->f_mode & FMODE_WRITE))
317 return -EBADF;
318 if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
319 return -EINVAL;
320 if (unlikely(!access_ok(VERIFY_READ, buf, count)))
321 return -EFAULT;
322
323 ret = rw_verify_area(WRITE, file, pos, count);
e28cc715
LT
324 if (ret >= 0) {
325 count = ret;
1da177e4
LT
326 ret = security_file_permission (file, MAY_WRITE);
327 if (!ret) {
328 if (file->f_op->write)
329 ret = file->f_op->write(file, buf, count, pos);
330 else
331 ret = do_sync_write(file, buf, count, pos);
332 if (ret > 0) {
0eeca283 333 fsnotify_modify(file->f_dentry);
1da177e4
LT
334 current->wchar += ret;
335 }
336 current->syscw++;
337 }
338 }
339
340 return ret;
341}
342
343EXPORT_SYMBOL(vfs_write);
344
345static inline loff_t file_pos_read(struct file *file)
346{
347 return file->f_pos;
348}
349
350static inline void file_pos_write(struct file *file, loff_t pos)
351{
352 file->f_pos = pos;
353}
354
355asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
356{
357 struct file *file;
358 ssize_t ret = -EBADF;
359 int fput_needed;
360
361 file = fget_light(fd, &fput_needed);
362 if (file) {
363 loff_t pos = file_pos_read(file);
364 ret = vfs_read(file, buf, count, &pos);
365 file_pos_write(file, pos);
366 fput_light(file, fput_needed);
367 }
368
369 return ret;
370}
371EXPORT_SYMBOL_GPL(sys_read);
372
373asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
374{
375 struct file *file;
376 ssize_t ret = -EBADF;
377 int fput_needed;
378
379 file = fget_light(fd, &fput_needed);
380 if (file) {
381 loff_t pos = file_pos_read(file);
382 ret = vfs_write(file, buf, count, &pos);
383 file_pos_write(file, pos);
384 fput_light(file, fput_needed);
385 }
386
387 return ret;
388}
389
390asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
391 size_t count, loff_t pos)
392{
393 struct file *file;
394 ssize_t ret = -EBADF;
395 int fput_needed;
396
397 if (pos < 0)
398 return -EINVAL;
399
400 file = fget_light(fd, &fput_needed);
401 if (file) {
402 ret = -ESPIPE;
403 if (file->f_mode & FMODE_PREAD)
404 ret = vfs_read(file, buf, count, &pos);
405 fput_light(file, fput_needed);
406 }
407
408 return ret;
409}
410
411asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
412 size_t count, loff_t pos)
413{
414 struct file *file;
415 ssize_t ret = -EBADF;
416 int fput_needed;
417
418 if (pos < 0)
419 return -EINVAL;
420
421 file = fget_light(fd, &fput_needed);
422 if (file) {
423 ret = -ESPIPE;
424 if (file->f_mode & FMODE_PWRITE)
425 ret = vfs_write(file, buf, count, &pos);
426 fput_light(file, fput_needed);
427 }
428
429 return ret;
430}
431
432/*
433 * Reduce an iovec's length in-place. Return the resulting number of segments
434 */
435unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
436{
437 unsigned long seg = 0;
438 size_t len = 0;
439
440 while (seg < nr_segs) {
441 seg++;
442 if (len + iov->iov_len >= to) {
443 iov->iov_len = to - len;
444 break;
445 }
446 len += iov->iov_len;
447 iov++;
448 }
449 return seg;
450}
451
69c3a5b8 452EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */
1da177e4 453
ee0b3e67
BP
454ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
455 unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
456{
457 struct kiocb kiocb;
458 ssize_t ret;
459
460 init_sync_kiocb(&kiocb, filp);
461 kiocb.ki_pos = *ppos;
462 kiocb.ki_left = len;
463 kiocb.ki_nbytes = len;
464
465 for (;;) {
466 ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
467 if (ret != -EIOCBRETRY)
468 break;
469 wait_on_retry_sync_kiocb(&kiocb);
470 }
471
472 if (ret == -EIOCBQUEUED)
473 ret = wait_on_sync_kiocb(&kiocb);
474 *ppos = kiocb.ki_pos;
475 return ret;
476}
477
478/* Do it by hand, with file-ops */
479ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
480 unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
481{
482 struct iovec *vector = iov;
483 ssize_t ret = 0;
484
485 while (nr_segs > 0) {
486 void __user *base;
487 size_t len;
488 ssize_t nr;
489
490 base = vector->iov_base;
491 len = vector->iov_len;
492 vector++;
493 nr_segs--;
494
495 nr = fn(filp, base, len, ppos);
496
497 if (nr < 0) {
498 if (!ret)
499 ret = nr;
500 break;
501 }
502 ret += nr;
503 if (nr != len)
504 break;
505 }
506
507 return ret;
508}
509
1da177e4
LT
510/* A write operation does a read from user space and vice versa */
511#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
512
513static ssize_t do_readv_writev(int type, struct file *file,
514 const struct iovec __user * uvector,
515 unsigned long nr_segs, loff_t *pos)
516{
1da177e4
LT
517 size_t tot_len;
518 struct iovec iovstack[UIO_FASTIOV];
ee0b3e67 519 struct iovec *iov = iovstack;
1da177e4
LT
520 ssize_t ret;
521 int seg;
522 io_fn_t fn;
523 iov_fn_t fnv;
524
525 /*
526 * SuS says "The readv() function *may* fail if the iovcnt argument
527 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
528 * traditionally returned zero for zero segments, so...
529 */
530 ret = 0;
531 if (nr_segs == 0)
532 goto out;
533
534 /*
535 * First get the "struct iovec" from user memory and
536 * verify all the pointers
537 */
538 ret = -EINVAL;
6cc6b122 539 if (nr_segs > UIO_MAXIOV)
1da177e4
LT
540 goto out;
541 if (!file->f_op)
542 goto out;
543 if (nr_segs > UIO_FASTIOV) {
544 ret = -ENOMEM;
545 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
546 if (!iov)
547 goto out;
548 }
549 ret = -EFAULT;
550 if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
551 goto out;
552
553 /*
554 * Single unix specification:
555 * We should -EINVAL if an element length is not >= 0 and fitting an
556 * ssize_t. The total length is fitting an ssize_t
557 *
558 * Be careful here because iov_len is a size_t not an ssize_t
559 */
560 tot_len = 0;
561 ret = -EINVAL;
562 for (seg = 0; seg < nr_segs; seg++) {
563 void __user *buf = iov[seg].iov_base;
564 ssize_t len = (ssize_t)iov[seg].iov_len;
565
1da177e4
LT
566 if (len < 0) /* size_t not fitting an ssize_t .. */
567 goto out;
1f08ad02
DH
568 if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
569 goto Efault;
1da177e4
LT
570 tot_len += len;
571 if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
572 goto out;
573 }
574 if (tot_len == 0) {
575 ret = 0;
576 goto out;
577 }
578
579 ret = rw_verify_area(type, file, pos, tot_len);
e28cc715 580 if (ret < 0)
411b67b4
KB
581 goto out;
582 ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
1da177e4
LT
583 if (ret)
584 goto out;
585
586 fnv = NULL;
587 if (type == READ) {
588 fn = file->f_op->read;
ee0b3e67 589 fnv = file->f_op->aio_read;
1da177e4
LT
590 } else {
591 fn = (io_fn_t)file->f_op->write;
ee0b3e67 592 fnv = file->f_op->aio_write;
1da177e4
LT
593 }
594
ee0b3e67
BP
595 if (fnv)
596 ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
597 pos, fnv);
598 else
599 ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
1da177e4 600
1da177e4
LT
601out:
602 if (iov != iovstack)
603 kfree(iov);
0eeca283
RL
604 if ((ret + (type == READ)) > 0) {
605 if (type == READ)
606 fsnotify_access(file->f_dentry);
607 else
608 fsnotify_modify(file->f_dentry);
609 }
1da177e4
LT
610 return ret;
611Efault:
612 ret = -EFAULT;
613 goto out;
614}
615
616ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
617 unsigned long vlen, loff_t *pos)
618{
619 if (!(file->f_mode & FMODE_READ))
620 return -EBADF;
ee0b3e67 621 if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
1da177e4
LT
622 return -EINVAL;
623
624 return do_readv_writev(READ, file, vec, vlen, pos);
625}
626
627EXPORT_SYMBOL(vfs_readv);
628
629ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
630 unsigned long vlen, loff_t *pos)
631{
632 if (!(file->f_mode & FMODE_WRITE))
633 return -EBADF;
ee0b3e67 634 if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
1da177e4
LT
635 return -EINVAL;
636
637 return do_readv_writev(WRITE, file, vec, vlen, pos);
638}
639
640EXPORT_SYMBOL(vfs_writev);
641
642asmlinkage ssize_t
643sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
644{
645 struct file *file;
646 ssize_t ret = -EBADF;
647 int fput_needed;
648
649 file = fget_light(fd, &fput_needed);
650 if (file) {
651 loff_t pos = file_pos_read(file);
652 ret = vfs_readv(file, vec, vlen, &pos);
653 file_pos_write(file, pos);
654 fput_light(file, fput_needed);
655 }
656
657 if (ret > 0)
658 current->rchar += ret;
659 current->syscr++;
660 return ret;
661}
662
663asmlinkage ssize_t
664sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
665{
666 struct file *file;
667 ssize_t ret = -EBADF;
668 int fput_needed;
669
670 file = fget_light(fd, &fput_needed);
671 if (file) {
672 loff_t pos = file_pos_read(file);
673 ret = vfs_writev(file, vec, vlen, &pos);
674 file_pos_write(file, pos);
675 fput_light(file, fput_needed);
676 }
677
678 if (ret > 0)
679 current->wchar += ret;
680 current->syscw++;
681 return ret;
682}
683
684static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
685 size_t count, loff_t max)
686{
687 struct file * in_file, * out_file;
688 struct inode * in_inode, * out_inode;
689 loff_t pos;
690 ssize_t retval;
691 int fput_needed_in, fput_needed_out;
692
693 /*
694 * Get input file, and verify that it is ok..
695 */
696 retval = -EBADF;
697 in_file = fget_light(in_fd, &fput_needed_in);
698 if (!in_file)
699 goto out;
700 if (!(in_file->f_mode & FMODE_READ))
701 goto fput_in;
702 retval = -EINVAL;
703 in_inode = in_file->f_dentry->d_inode;
704 if (!in_inode)
705 goto fput_in;
706 if (!in_file->f_op || !in_file->f_op->sendfile)
707 goto fput_in;
708 retval = -ESPIPE;
709 if (!ppos)
710 ppos = &in_file->f_pos;
711 else
712 if (!(in_file->f_mode & FMODE_PREAD))
713 goto fput_in;
714 retval = rw_verify_area(READ, in_file, ppos, count);
e28cc715 715 if (retval < 0)
1da177e4 716 goto fput_in;
e28cc715 717 count = retval;
1da177e4
LT
718
719 retval = security_file_permission (in_file, MAY_READ);
720 if (retval)
721 goto fput_in;
722
723 /*
724 * Get output file, and verify that it is ok..
725 */
726 retval = -EBADF;
727 out_file = fget_light(out_fd, &fput_needed_out);
728 if (!out_file)
729 goto fput_in;
730 if (!(out_file->f_mode & FMODE_WRITE))
731 goto fput_out;
732 retval = -EINVAL;
733 if (!out_file->f_op || !out_file->f_op->sendpage)
734 goto fput_out;
735 out_inode = out_file->f_dentry->d_inode;
736 retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
e28cc715 737 if (retval < 0)
1da177e4 738 goto fput_out;
e28cc715 739 count = retval;
1da177e4
LT
740
741 retval = security_file_permission (out_file, MAY_WRITE);
742 if (retval)
743 goto fput_out;
744
745 if (!max)
746 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
747
748 pos = *ppos;
749 retval = -EINVAL;
750 if (unlikely(pos < 0))
751 goto fput_out;
752 if (unlikely(pos + count > max)) {
753 retval = -EOVERFLOW;
754 if (pos >= max)
755 goto fput_out;
756 count = max - pos;
757 }
758
759 retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
760
761 if (retval > 0) {
762 current->rchar += retval;
763 current->wchar += retval;
764 }
765 current->syscr++;
766 current->syscw++;
767
768 if (*ppos > max)
769 retval = -EOVERFLOW;
770
771fput_out:
772 fput_light(out_file, fput_needed_out);
773fput_in:
774 fput_light(in_file, fput_needed_in);
775out:
776 return retval;
777}
778
779asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
780{
781 loff_t pos;
782 off_t off;
783 ssize_t ret;
784
785 if (offset) {
786 if (unlikely(get_user(off, offset)))
787 return -EFAULT;
788 pos = off;
789 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
790 if (unlikely(put_user(pos, offset)))
791 return -EFAULT;
792 return ret;
793 }
794
795 return do_sendfile(out_fd, in_fd, NULL, count, 0);
796}
797
798asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
799{
800 loff_t pos;
801 ssize_t ret;
802
803 if (offset) {
804 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
805 return -EFAULT;
806 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
807 if (unlikely(put_user(pos, offset)))
808 return -EFAULT;
809 return ret;
810 }
811
812 return do_sendfile(out_fd, in_fd, NULL, count, 0);
813}