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