upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[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/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 EXPORT_SYMBOL_GPL(sys_write);
348
349 asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
350                              size_t count, loff_t pos)
351 {
352         struct file *file;
353         ssize_t ret = -EBADF;
354         int fput_needed;
355
356         if (pos < 0)
357                 return -EINVAL;
358
359         file = fget_light(fd, &fput_needed);
360         if (file) {
361                 ret = -ESPIPE;
362                 if (file->f_mode & FMODE_PREAD)
363                         ret = vfs_read(file, buf, count, &pos);
364                 fput_light(file, fput_needed);
365         }
366
367         return ret;
368 }
369
370 asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
371                               size_t count, loff_t pos)
372 {
373         struct file *file;
374         ssize_t ret = -EBADF;
375         int fput_needed;
376
377         if (pos < 0)
378                 return -EINVAL;
379
380         file = fget_light(fd, &fput_needed);
381         if (file) {
382                 ret = -ESPIPE;
383                 if (file->f_mode & FMODE_PWRITE)  
384                         ret = vfs_write(file, buf, count, &pos);
385                 fput_light(file, fput_needed);
386         }
387
388         return ret;
389 }
390
391 /*
392  * Reduce an iovec's length in-place.  Return the resulting number of segments
393  */
394 unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
395 {
396         unsigned long seg = 0;
397         size_t len = 0;
398
399         while (seg < nr_segs) {
400                 seg++;
401                 if (len + iov->iov_len >= to) {
402                         iov->iov_len = to - len;
403                         break;
404                 }
405                 len += iov->iov_len;
406                 iov++;
407         }
408         return seg;
409 }
410
411 EXPORT_SYMBOL(iov_shorten);
412
413 /* A write operation does a read from user space and vice versa */
414 #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
415
416 static ssize_t do_readv_writev(int type, struct file *file,
417                                const struct iovec __user * uvector,
418                                unsigned long nr_segs, loff_t *pos)
419 {
420         typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
421         typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
422
423         size_t tot_len;
424         struct iovec iovstack[UIO_FASTIOV];
425         struct iovec *iov=iovstack, *vector;
426         ssize_t ret;
427         int seg;
428         io_fn_t fn;
429         iov_fn_t fnv;
430
431         /*
432          * SuS says "The readv() function *may* fail if the iovcnt argument
433          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
434          * traditionally returned zero for zero segments, so...
435          */
436         ret = 0;
437         if (nr_segs == 0)
438                 goto out;
439
440         /*
441          * First get the "struct iovec" from user memory and
442          * verify all the pointers
443          */
444         ret = -EINVAL;
445         if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
446                 goto out;
447         if (!file->f_op)
448                 goto out;
449         if (nr_segs > UIO_FASTIOV) {
450                 ret = -ENOMEM;
451                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
452                 if (!iov)
453                         goto out;
454         }
455         ret = -EFAULT;
456         if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
457                 goto out;
458
459         /*
460          * Single unix specification:
461          * We should -EINVAL if an element length is not >= 0 and fitting an
462          * ssize_t.  The total length is fitting an ssize_t
463          *
464          * Be careful here because iov_len is a size_t not an ssize_t
465          */
466         tot_len = 0;
467         ret = -EINVAL;
468         for (seg = 0; seg < nr_segs; seg++) {
469                 void __user *buf = iov[seg].iov_base;
470                 ssize_t len = (ssize_t)iov[seg].iov_len;
471
472                 if (len < 0)    /* size_t not fitting an ssize_t .. */
473                         goto out;
474                 if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
475                         goto Efault;
476                 tot_len += len;
477                 if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
478                         goto out;
479         }
480         if (tot_len == 0) {
481                 ret = 0;
482                 goto out;
483         }
484
485         ret = rw_verify_area(type, file, pos, tot_len);
486         if (ret)
487                 goto out;
488
489         fnv = NULL;
490         if (type == READ) {
491                 fn = file->f_op->read;
492                 fnv = file->f_op->readv;
493         } else {
494                 fn = (io_fn_t)file->f_op->write;
495                 fnv = file->f_op->writev;
496         }
497         if (fnv) {
498                 ret = fnv(file, iov, nr_segs, pos);
499                 goto out;
500         }
501
502         /* Do it by hand, with file-ops */
503         ret = 0;
504         vector = iov;
505         while (nr_segs > 0) {
506                 void __user * base;
507                 size_t len;
508                 ssize_t nr;
509
510                 base = vector->iov_base;
511                 len = vector->iov_len;
512                 vector++;
513                 nr_segs--;
514
515                 nr = fn(file, base, len, pos);
516
517                 if (nr < 0) {
518                         if (!ret) ret = nr;
519                         break;
520                 }
521                 ret += nr;
522                 if (nr != len)
523                         break;
524         }
525 out:
526         if (iov != iovstack)
527                 kfree(iov);
528         if ((ret + (type == READ)) > 0)
529                 dnotify_parent(file->f_dentry,
530                                 (type == READ) ? DN_ACCESS : DN_MODIFY);
531         return ret;
532 Efault:
533         ret = -EFAULT;
534         goto out;
535 }
536
537 ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
538                   unsigned long vlen, loff_t *pos)
539 {
540         if (!(file->f_mode & FMODE_READ))
541                 return -EBADF;
542         if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
543                 return -EINVAL;
544
545         return do_readv_writev(READ, file, vec, vlen, pos);
546 }
547
548 EXPORT_SYMBOL(vfs_readv);
549
550 ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
551                    unsigned long vlen, loff_t *pos)
552 {
553         if (!(file->f_mode & FMODE_WRITE))
554                 return -EBADF;
555         if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
556                 return -EINVAL;
557
558         return do_readv_writev(WRITE, file, vec, vlen, pos);
559 }
560
561 EXPORT_SYMBOL(vfs_writev);
562
563 asmlinkage ssize_t
564 sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
565 {
566         struct file *file;
567         ssize_t ret = -EBADF;
568         int fput_needed;
569
570         file = fget_light(fd, &fput_needed);
571         if (file) {
572                 loff_t pos = file_pos_read(file);
573                 ret = vfs_readv(file, vec, vlen, &pos);
574                 file_pos_write(file, pos);
575                 fput_light(file, fput_needed);
576         }
577
578         if (ret > 0)
579                 current->rchar += ret;
580         current->syscr++;
581         return ret;
582 }
583
584 asmlinkage ssize_t
585 sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
586 {
587         struct file *file;
588         ssize_t ret = -EBADF;
589         int fput_needed;
590
591         file = fget_light(fd, &fput_needed);
592         if (file) {
593                 loff_t pos = file_pos_read(file);
594                 ret = vfs_writev(file, vec, vlen, &pos);
595                 file_pos_write(file, pos);
596                 fput_light(file, fput_needed);
597         }
598
599         if (ret > 0)
600                 current->wchar += ret;
601         current->syscw++;
602         return ret;
603 }
604
605 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
606                            size_t count, loff_t max)
607 {
608         struct file * in_file, * out_file;
609         struct inode * in_inode, * out_inode;
610         loff_t pos;
611         ssize_t retval;
612         int fput_needed_in, fput_needed_out;
613
614         /*
615          * Get input file, and verify that it is ok..
616          */
617         retval = -EBADF;
618         in_file = fget_light(in_fd, &fput_needed_in);
619         if (!in_file)
620                 goto out;
621         if (!(in_file->f_mode & FMODE_READ))
622                 goto fput_in;
623         retval = -EINVAL;
624         in_inode = in_file->f_dentry->d_inode;
625         if (!in_inode)
626                 goto fput_in;
627         if (!in_file->f_op || !in_file->f_op->sendfile)
628                 goto fput_in;
629         retval = -ESPIPE;
630         if (!ppos)
631                 ppos = &in_file->f_pos;
632         else
633                 if (!(in_file->f_mode & FMODE_PREAD))
634                         goto fput_in;
635         retval = rw_verify_area(READ, in_file, ppos, count);
636         if (retval)
637                 goto fput_in;
638
639         retval = security_file_permission (in_file, MAY_READ);
640         if (retval)
641                 goto fput_in;
642
643         /*
644          * Get output file, and verify that it is ok..
645          */
646         retval = -EBADF;
647         out_file = fget_light(out_fd, &fput_needed_out);
648         if (!out_file)
649                 goto fput_in;
650         if (!(out_file->f_mode & FMODE_WRITE))
651                 goto fput_out;
652         retval = -EINVAL;
653         if (!out_file->f_op || !out_file->f_op->sendpage)
654                 goto fput_out;
655         out_inode = out_file->f_dentry->d_inode;
656         retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
657         if (retval)
658                 goto fput_out;
659
660         retval = security_file_permission (out_file, MAY_WRITE);
661         if (retval)
662                 goto fput_out;
663
664         if (!max)
665                 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
666
667         pos = *ppos;
668         retval = -EINVAL;
669         if (unlikely(pos < 0))
670                 goto fput_out;
671         if (unlikely(pos + count > max)) {
672                 retval = -EOVERFLOW;
673                 if (pos >= max)
674                         goto fput_out;
675                 count = max - pos;
676         }
677
678         retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
679
680         if (retval > 0) {
681                 current->rchar += retval;
682                 current->wchar += retval;
683         }
684         current->syscr++;
685         current->syscw++;
686
687         if (*ppos > max)
688                 retval = -EOVERFLOW;
689
690 fput_out:
691         fput_light(out_file, fput_needed_out);
692 fput_in:
693         fput_light(in_file, fput_needed_in);
694 out:
695         return retval;
696 }
697
698 asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
699 {
700         loff_t pos;
701         off_t off;
702         ssize_t ret;
703
704         if (offset) {
705                 if (unlikely(get_user(off, offset)))
706                         return -EFAULT;
707                 pos = off;
708                 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
709                 if (unlikely(put_user(pos, offset)))
710                         return -EFAULT;
711                 return ret;
712         }
713
714         return do_sendfile(out_fd, in_fd, NULL, count, 0);
715 }
716
717 asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
718 {
719         loff_t pos;
720         ssize_t ret;
721
722         if (offset) {
723                 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
724                         return -EFAULT;
725                 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
726                 if (unlikely(put_user(pos, offset)))
727                         return -EFAULT;
728                 return ret;
729         }
730
731         return do_sendfile(out_fd, in_fd, NULL, count, 0);
732 }