[PATCH] Vectorize aio_read/aio_write fileop methods
[safe/jmp/linux-2.6] / 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
19 #include <asm/uaccess.h>
20 #include <asm/unistd.h>
21
22 const struct file_operations generic_ro_fops = {
23         .llseek         = generic_file_llseek,
24         .read           = generic_file_read,
25         .mmap           = generic_file_readonly_mmap,
26         .sendfile       = generic_file_sendfile,
27 };
28
29 EXPORT_SYMBOL(generic_ro_fops);
30
31 loff_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
36         mutex_lock(&inode->i_mutex);
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         }
52         mutex_unlock(&inode->i_mutex);
53         return retval;
54 }
55
56 EXPORT_SYMBOL(generic_file_llseek);
57
58 loff_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 }
81 EXPORT_SYMBOL(remote_llseek);
82
83 loff_t no_llseek(struct file *file, loff_t offset, int origin)
84 {
85         return -ESPIPE;
86 }
87 EXPORT_SYMBOL(no_llseek);
88
89 loff_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 }
112 EXPORT_SYMBOL(default_llseek);
113
114 loff_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 }
126 EXPORT_SYMBOL(vfs_llseek);
127
128 asmlinkage 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);
147 bad:
148         return retval;
149 }
150
151 #ifdef __ARCH_WANT_SYS_LLSEEK
152 asmlinkage 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         }
179 out_putf:
180         fput_light(file, fput_needed);
181 bad:
182         return retval;
183 }
184 #endif
185
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)
192
193 int 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
198         if (unlikely((ssize_t) count < 0))
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;
205         if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
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;
213
214 Einval:
215         return -EINVAL;
216 }
217
218 static 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
228 ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
229 {
230         struct iovec iov = { .iov_base = buf, .iov_len = len };
231         struct kiocb kiocb;
232         ssize_t ret;
233
234         init_sync_kiocb(&kiocb, filp);
235         kiocb.ki_pos = *ppos;
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;
242                 wait_on_retry_sync_kiocb(&kiocb);
243         }
244
245         if (-EIOCBQUEUED == ret)
246                 ret = wait_on_sync_kiocb(&kiocb);
247         *ppos = kiocb.ki_pos;
248         return ret;
249 }
250
251 EXPORT_SYMBOL(do_sync_read);
252
253 ssize_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);
265         if (ret >= 0) {
266                 count = ret;
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) {
274                                 fsnotify_access(file->f_dentry);
275                                 current->rchar += ret;
276                         }
277                         current->syscr++;
278                 }
279         }
280
281         return ret;
282 }
283
284 EXPORT_SYMBOL(vfs_read);
285
286 ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
287 {
288         struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
289         struct kiocb kiocb;
290         ssize_t ret;
291
292         init_sync_kiocb(&kiocb, filp);
293         kiocb.ki_pos = *ppos;
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;
300                 wait_on_retry_sync_kiocb(&kiocb);
301         }
302
303         if (-EIOCBQUEUED == ret)
304                 ret = wait_on_sync_kiocb(&kiocb);
305         *ppos = kiocb.ki_pos;
306         return ret;
307 }
308
309 EXPORT_SYMBOL(do_sync_write);
310
311 ssize_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);
323         if (ret >= 0) {
324                 count = ret;
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) {
332                                 fsnotify_modify(file->f_dentry);
333                                 current->wchar += ret;
334                         }
335                         current->syscw++;
336                 }
337         }
338
339         return ret;
340 }
341
342 EXPORT_SYMBOL(vfs_write);
343
344 static inline loff_t file_pos_read(struct file *file)
345 {
346         return file->f_pos;
347 }
348
349 static inline void file_pos_write(struct file *file, loff_t pos)
350 {
351         file->f_pos = pos;
352 }
353
354 asmlinkage 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 }
370 EXPORT_SYMBOL_GPL(sys_read);
371
372 asmlinkage 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
389 asmlinkage 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
410 asmlinkage 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  */
434 unsigned 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
451 EXPORT_UNUSED_SYMBOL(iov_shorten);  /*  June 2006  */
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
456 static 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;
485         if (nr_segs > UIO_MAXIOV)
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
512                 if (len < 0)    /* size_t not fitting an ssize_t .. */
513                         goto out;
514                 if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
515                         goto Efault;
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);
526         if (ret < 0)
527                 goto out;
528         ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
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         }
568 out:
569         if (iov != iovstack)
570                 kfree(iov);
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         }
577         return ret;
578 Efault:
579         ret = -EFAULT;
580         goto out;
581 }
582
583 ssize_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
594 EXPORT_SYMBOL(vfs_readv);
595
596 ssize_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
607 EXPORT_SYMBOL(vfs_writev);
608
609 asmlinkage ssize_t
610 sys_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
630 asmlinkage ssize_t
631 sys_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
651 static 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);
682         if (retval < 0)
683                 goto fput_in;
684         count = retval;
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);
704         if (retval < 0)
705                 goto fput_out;
706         count = retval;
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
738 fput_out:
739         fput_light(out_file, fput_needed_out);
740 fput_in:
741         fput_light(in_file, fput_needed_in);
742 out:
743         return retval;
744 }
745
746 asmlinkage 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
765 asmlinkage 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 }