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