[PATCH] Remove readv/writev methods and use aio_read/aio_write instead
[linux-2.6.git] / fs / read_write.c
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>
13 #include <linux/fsnotify.h>
14 #include <linux/security.h>
15 #include <linux/module.h>
16 #include <linux/syscalls.h>
17 #include <linux/pagemap.h>
18 #include "read_write.h"
19
20 #include <asm/uaccess.h>
21 #include <asm/unistd.h>
22
23 const struct file_operations generic_ro_fops = {
24         .llseek         = generic_file_llseek,
25         .read           = generic_file_read,
26         .mmap           = generic_file_readonly_mmap,
27         .sendfile       = generic_file_sendfile,
28 };
29
30 EXPORT_SYMBOL(generic_ro_fops);
31
32 loff_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
37         mutex_lock(&inode->i_mutex);
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         }
53         mutex_unlock(&inode->i_mutex);
54         return retval;
55 }
56
57 EXPORT_SYMBOL(generic_file_llseek);
58
59 loff_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 }
82 EXPORT_SYMBOL(remote_llseek);
83
84 loff_t no_llseek(struct file *file, loff_t offset, int origin)
85 {
86         return -ESPIPE;
87 }
88 EXPORT_SYMBOL(no_llseek);
89
90 loff_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 }
113 EXPORT_SYMBOL(default_llseek);
114
115 loff_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 }
127 EXPORT_SYMBOL(vfs_llseek);
128
129 asmlinkage 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);
148 bad:
149         return retval;
150 }
151
152 #ifdef __ARCH_WANT_SYS_LLSEEK
153 asmlinkage 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         }
180 out_putf:
181         fput_light(file, fput_needed);
182 bad:
183         return retval;
184 }
185 #endif
186
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)
193
194 int 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
199         if (unlikely((ssize_t) count < 0))
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;
206         if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
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;
214
215 Einval:
216         return -EINVAL;
217 }
218
219 static 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
229 ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
230 {
231         struct iovec iov = { .iov_base = buf, .iov_len = len };
232         struct kiocb kiocb;
233         ssize_t ret;
234
235         init_sync_kiocb(&kiocb, filp);
236         kiocb.ki_pos = *ppos;
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;
243                 wait_on_retry_sync_kiocb(&kiocb);
244         }
245
246         if (-EIOCBQUEUED == ret)
247                 ret = wait_on_sync_kiocb(&kiocb);
248         *ppos = kiocb.ki_pos;
249         return ret;
250 }
251
252 EXPORT_SYMBOL(do_sync_read);
253
254 ssize_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);
266         if (ret >= 0) {
267                 count = ret;
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) {
275                                 fsnotify_access(file->f_dentry);
276                                 current->rchar += ret;
277                         }
278                         current->syscr++;
279                 }
280         }
281
282         return ret;
283 }
284
285 EXPORT_SYMBOL(vfs_read);
286
287 ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
288 {
289         struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
290         struct kiocb kiocb;
291         ssize_t ret;
292
293         init_sync_kiocb(&kiocb, filp);
294         kiocb.ki_pos = *ppos;
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;
301                 wait_on_retry_sync_kiocb(&kiocb);
302         }
303
304         if (-EIOCBQUEUED == ret)
305                 ret = wait_on_sync_kiocb(&kiocb);
306         *ppos = kiocb.ki_pos;
307         return ret;
308 }
309
310 EXPORT_SYMBOL(do_sync_write);
311
312 ssize_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);
324         if (ret >= 0) {
325                 count = ret;
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) {
333                                 fsnotify_modify(file->f_dentry);
334                                 current->wchar += ret;
335                         }
336                         current->syscw++;
337                 }
338         }
339
340         return ret;
341 }
342
343 EXPORT_SYMBOL(vfs_write);
344
345 static inline loff_t file_pos_read(struct file *file)
346 {
347         return file->f_pos;
348 }
349
350 static inline void file_pos_write(struct file *file, loff_t pos)
351 {
352         file->f_pos = pos;
353 }
354
355 asmlinkage 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 }
371 EXPORT_SYMBOL_GPL(sys_read);
372
373 asmlinkage 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
390 asmlinkage 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
411 asmlinkage 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  */
435 unsigned 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
452 EXPORT_UNUSED_SYMBOL(iov_shorten);  /*  June 2006  */
453
454 ssize_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 */
479 ssize_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
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
513 static 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 {
517         size_t tot_len;
518         struct iovec iovstack[UIO_FASTIOV];
519         struct iovec *iov = iovstack;
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;
539         if (nr_segs > UIO_MAXIOV)
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
566                 if (len < 0)    /* size_t not fitting an ssize_t .. */
567                         goto out;
568                 if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
569                         goto Efault;
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);
580         if (ret < 0)
581                 goto out;
582         ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
583         if (ret)
584                 goto out;
585
586         fnv = NULL;
587         if (type == READ) {
588                 fn = file->f_op->read;
589                 fnv = file->f_op->aio_read;
590         } else {
591                 fn = (io_fn_t)file->f_op->write;
592                 fnv = file->f_op->aio_write;
593         }
594
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);
600
601 out:
602         if (iov != iovstack)
603                 kfree(iov);
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         }
610         return ret;
611 Efault:
612         ret = -EFAULT;
613         goto out;
614 }
615
616 ssize_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;
621         if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
622                 return -EINVAL;
623
624         return do_readv_writev(READ, file, vec, vlen, pos);
625 }
626
627 EXPORT_SYMBOL(vfs_readv);
628
629 ssize_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;
634         if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
635                 return -EINVAL;
636
637         return do_readv_writev(WRITE, file, vec, vlen, pos);
638 }
639
640 EXPORT_SYMBOL(vfs_writev);
641
642 asmlinkage ssize_t
643 sys_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
663 asmlinkage ssize_t
664 sys_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
684 static 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);
715         if (retval < 0)
716                 goto fput_in;
717         count = retval;
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);
737         if (retval < 0)
738                 goto fput_out;
739         count = retval;
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
771 fput_out:
772         fput_light(out_file, fput_needed_out);
773 fput_in:
774         fput_light(in_file, fput_needed_in);
775 out:
776         return retval;
777 }
778
779 asmlinkage 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
798 asmlinkage 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 }