root/fs/read_write.c

Revision 28, 15.4 kB (checked in by dkaplan1, 6 years ago)

Commented files

Line 
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
17 #include <asm/uaccess.h>
18 #include <asm/unistd.h>
19 #include <asm/callgate.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
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
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
114 EXPORT_SYMBOL(default_llseek);
115
116 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
117 {
118         loff_t (*fn)(struct file *, loff_t, int);
119
120         fn = default_llseek;
121         if (file->f_op && file->f_op->llseek)
122                 fn = file->f_op->llseek;
123         return fn(file, offset, origin);
124 }
125
126 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
127 {
128         off_t retval;
129         struct file * file;
130         int fput_needed;
131
132         retval = -EBADF;
133         file = fget_light(fd, &fput_needed);
134         if (!file)
135                 goto bad;
136
137         retval = -EINVAL;
138         if (origin <= 2) {
139                 loff_t res = llseek(file, offset, origin);
140                 retval = res;
141                 if (res != (loff_t)retval)
142                         retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
143         }
144         fput_light(file, fput_needed);
145 bad:
146         return retval;
147 }
148 EXPORT_SYMBOL_GPL(sys_lseek);
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 = 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 ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
186 {
187         struct kiocb kiocb;
188         ssize_t ret;
189
190         init_sync_kiocb(&kiocb, filp);
191         kiocb.ki_pos = *ppos;
192         if ((unsigned long) filp->f_op->aio_read > PAGE_OFFSET) //kernel
193                 ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos);
194         else {
195                 //Well, the last parameter is actually 64-bits
196                 //We could deal with this, it would require extra work though
197                 //Let's just assume no one will ever call this function
198                 CALLDRIVER_PREP4(aio, &kiocb, buf, len, (unsigned long) kiocb.ki_pos)
199                 ret = calldriver((unsigned long) filp->f_op->aio_read, aio_args,aio_sizes, 4, current->mm, 1, 0);
200         }
201
202         if (-EIOCBQUEUED == ret)
203                 ret = wait_on_sync_kiocb(&kiocb);
204         *ppos = kiocb.ki_pos;
205         return ret;
206 }
207
208 EXPORT_SYMBOL(do_sync_read);
209
210 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
211 {
212         struct inode *inode = file->f_dentry->d_inode;
213         ssize_t ret;
214
215         if (!(file->f_mode & FMODE_READ))
216                 return -EBADF;
217         if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
218                 return -EINVAL;
219
220         ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
221         if (!ret) {
222                 ret = security_file_permission (file, MAY_READ);
223                 if (!ret) {
224                         if (file->f_op->read) {
225                                 if ((unsigned long) file->f_op->read > PAGE_OFFSET) //kernel
226                                         ret = file->f_op->read(file, buf, count, pos);
227                                 else {
228                                         CALLDRIVER_PREP4(read, file, buf, count, pos)
229               read_sizes[0]=sizeof(*file);
230           read_sizes[3]=sizeof(*pos);
231                                         ret = calldriver((unsigned long) file->f_op->read, read_args, read_sizes, 4, current->mm, 9, 0);
232                                 }
233                         }
234                         else
235                                 ret = do_sync_read(file, buf, count, pos);
236                         if (ret > 0)
237                                 dnotify_parent(file->f_dentry, DN_ACCESS);
238                 }
239         }
240
241         return ret;
242 }
243
244 EXPORT_SYMBOL(vfs_read);
245
246 ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
247 {
248         struct kiocb kiocb;
249         ssize_t ret;
250
251         init_sync_kiocb(&kiocb, filp);
252         kiocb.ki_pos = *ppos;
253         if ((unsigned long) filp->f_op->aio_write > PAGE_OFFSET) //kernel
254                 ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos);
255         else {
256                 //See commend about aio_read
257                 CALLDRIVER_PREP4(aio, &kiocb, buf, len, (unsigned long) kiocb.ki_pos)
258                 ret = calldriver((unsigned long) filp->f_op->aio_write, aio_args, aio_sizes, 4, current->mm, 1, 0);
259         }
260
261
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         struct inode *inode = file->f_dentry->d_inode;
273         ssize_t ret;
274
275         if (!(file->f_mode & FMODE_WRITE))
276                 return -EBADF;
277         if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
278                 return -EINVAL;
279
280         ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
281         if (!ret) {
282                 ret = security_file_permission (file, MAY_WRITE);
283                 if (!ret) {
284                         if (file->f_op->write) {
285                                 if ((unsigned long) file->f_op->write > PAGE_OFFSET) //kernel
286                                         ret = file->f_op->write(file, buf, count, pos);
287                                 else {
288                                         CALLDRIVER_PREP4(write, file, buf, count, pos)
289                                         ret = calldriver((unsigned long) file->f_op->write, write_args, write_sizes, 4, current->mm, 9, 0);
290                                 }
291                         }
292                         else
293                                 ret = do_sync_write(file, buf, count, pos);
294                         if (ret > 0)
295                                 dnotify_parent(file->f_dentry, DN_MODIFY);
296                 }
297         }
298
299         return ret;
300 }
301
302 EXPORT_SYMBOL(vfs_write);
303
304 asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
305 {
306         struct file *file;
307         ssize_t ret = -EBADF;
308         int fput_needed;
309
310         file = fget_light(fd, &fput_needed);
311         if (file) {
312                 ret = vfs_read(file, buf, count, &file->f_pos);
313                 fput_light(file, fput_needed);
314         }
315
316         return ret;
317 }
318 EXPORT_SYMBOL_GPL(sys_read);
319
320 asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
321 {
322         struct file *file;
323         ssize_t ret = -EBADF;
324         int fput_needed;
325
326         file = fget_light(fd, &fput_needed);
327         if (file) {
328                 ret = vfs_write(file, buf, count, &file->f_pos);
329                 fput_light(file, fput_needed);
330         }
331
332         return ret;
333 }
334
335 asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
336                              size_t count, loff_t pos)
337 {
338         struct file *file;
339         ssize_t ret = -EBADF;
340         int fput_needed;
341
342         if (pos < 0)
343                 return -EINVAL;
344
345         file = fget_light(fd, &fput_needed);
346         if (file) {
347                 ret = vfs_read(file, buf, count, &pos);
348                 fput_light(file, fput_needed);
349         }
350
351         return ret;
352 }
353
354 asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
355                               size_t count, loff_t pos)
356 {
357         struct file *file;
358         ssize_t ret = -EBADF;
359         int fput_needed;
360
361         if (pos < 0)
362                 return -EINVAL;
363
364         file = fget_light(fd, &fput_needed);
365         if (file) {
366                 ret = vfs_write(file, buf, count, &pos);
367                 fput_light(file, fput_needed);
368         }
369
370         return ret;
371 }
372
373 /*
374  * Reduce an iovec's length in-place.  Return the resulting number of segments
375  */
376 unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
377 {
378         unsigned long seg = 0;
379         size_t len = 0;
380
381         while (seg < nr_segs) {
382                 seg++;
383                 if (len + iov->iov_len >= to) {
384                         iov->iov_len = to - len;
385                         break;
386                 }
387                 len += iov->iov_len;
388                 iov++;
389         }
390         return seg;
391 }
392
393 EXPORT_SYMBOL(iov_shorten);
394
395 static ssize_t do_readv_writev(int type, struct file *file,
396                                const struct iovec __user * uvector,
397                                unsigned long nr_segs, loff_t *pos)
398 {
399         typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
400         typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
401
402         size_t tot_len;
403         struct iovec iovstack[UIO_FASTIOV];
404         struct iovec *iov=iovstack, *vector;
405         ssize_t ret;
406         int seg;
407         io_fn_t fn;
408         iov_fn_t fnv;
409         struct inode *inode;
410
411         /*
412          * SuS says "The readv() function *may* fail if the iovcnt argument
413          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
414          * traditionally returned zero for zero segments, so...
415          */
416         ret = 0;
417         if (nr_segs == 0)
418                 goto out;
419
420         /*
421          * First get the "struct iovec" from user memory and
422          * verify all the pointers
423          */
424         ret = -EINVAL;
425         if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
426                 goto out;
427         if (!file->f_op)
428                 goto out;
429         if (nr_segs > UIO_FASTIOV) {
430                 ret = -ENOMEM;
431                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
432                 if (!iov)
433                         goto out;
434         }
435         ret = -EFAULT;
436         if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
437                 goto out;
438
439         /*
440          * Single unix specification:
441          * We should -EINVAL if an element length is not >= 0 and fitting an
442          * ssize_t.  The total length is fitting an ssize_t
443          *
444          * Be careful here because iov_len is a size_t not an ssize_t
445          */
446         tot_len = 0;
447         ret = -EINVAL;
448         for (seg = 0; seg < nr_segs; seg++) {
449                 ssize_t len = (ssize_t)iov[seg].iov_len;
450
451                 if (len < 0)    /* size_t not fitting an ssize_t .. */
452                         goto out;
453                 tot_len += len;
454                 if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
455                         goto out;
456         }
457         if (tot_len == 0) {
458                 ret = 0;
459                 goto out;
460         }
461
462         inode = file->f_dentry->d_inode;
463         /* VERIFY_WRITE actually means a read, as we write to user space */
464         ret = locks_verify_area((type == READ
465                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
466                                 inode, file, *pos, tot_len);
467         if (ret)
468                 goto out;
469
470         fnv = NULL;
471         if (type == READ) {
472                 fn = file->f_op->read;
473                 fnv = file->f_op->readv;
474         } else {
475                 fn = (io_fn_t)file->f_op->write;
476                 fnv = file->f_op->writev;
477         }
478         if (fnv) {
479                 ret = fnv(file, iov, nr_segs, pos);
480                 goto out;
481         }
482
483         /* Do it by hand, with file-ops */
484         ret = 0;
485         vector = iov;
486         while (nr_segs > 0) {
487                 void __user * base;
488                 size_t len;
489                 ssize_t nr;
490
491                 base = vector->iov_base;
492                 len = vector->iov_len;
493                 vector++;
494                 nr_segs--;
495
496                 nr = fn(file, base, len, pos);
497
498                 if (nr < 0) {
499                         if (!ret) ret = nr;
500                         break;
501                 }
502                 ret += nr;
503                 if (nr != len)
504                         break;
505         }
506 out:
507         if (iov != iovstack)
508                 kfree(iov);
509         if ((ret + (type == READ)) > 0)
510                 dnotify_parent(file->f_dentry,
511                                 (type == READ) ? DN_ACCESS : DN_MODIFY);
512         return ret;
513 }
514
515 ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
516                   unsigned long vlen, loff_t *pos)
517 {
518         if (!(file->f_mode & FMODE_READ))
519                 return -EBADF;
520         if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
521                 return -EINVAL;
522
523         return do_readv_writev(READ, file, vec, vlen, pos);
524 }
525
526 EXPORT_SYMBOL(vfs_readv);
527
528 ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
529                    unsigned long vlen, loff_t *pos)
530 {
531         if (!(file->f_mode & FMODE_WRITE))
532                 return -EBADF;
533         if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
534                 return -EINVAL;
535
536         return do_readv_writev(WRITE, file, vec, vlen, pos);
537 }
538
539 EXPORT_SYMBOL(vfs_writev);
540
541 asmlinkage ssize_t
542 sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
543 {
544         struct file *file;
545         ssize_t ret = -EBADF;
546         int fput_needed;
547
548         file = fget_light(fd, &fput_needed);
549         if (file) {
550                 ret = vfs_readv(file, vec, vlen, &file->f_pos);
551                 fput_light(file, fput_needed);
552         }
553
554         return ret;
555 }
556
557 asmlinkage ssize_t
558 sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
559 {
560         struct file *file;
561         ssize_t ret = -EBADF;
562         int fput_needed;
563
564         file = fget_light(fd, &fput_needed);
565         if (file) {
566                 ret = vfs_writev(file, vec, vlen, &file->f_pos);
567                 fput_light(file, fput_needed);
568         }
569
570         return ret;
571 }
572
573 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
574                            size_t count, loff_t max)
575 {
576         struct file * in_file, * out_file;
577         struct inode * in_inode, * out_inode;
578         loff_t pos;
579         ssize_t retval;
580         int fput_needed_in, fput_needed_out;
581
582         /*
583          * Get input file, and verify that it is ok..
584          */
585         retval = -EBADF;
586         in_file = fget_light(in_fd, &fput_needed_in);
587         if (!in_file)
588                 goto out;
589         if (!(in_file->f_mode & FMODE_READ))
590                 goto fput_in;
591         retval = -EINVAL;
592         in_inode = in_file->f_dentry->d_inode;
593         if (!in_inode)
594                 goto fput_in;
595         if (!in_file->f_op || !in_file->f_op->sendfile)
596                 goto fput_in;
597         if (!ppos)
598                 ppos = &in_file->f_pos;
599         retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, *ppos, count);
600         if (retval)
601                 goto fput_in;
602
603         retval = security_file_permission (in_file, MAY_READ);
604         if (retval)
605                 goto fput_in;
606
607         /*
608          * Get output file, and verify that it is ok..
609          */
610         retval = -EBADF;
611         out_file = fget_light(out_fd, &fput_needed_out);
612         if (!out_file)
613                 goto fput_in;
614         if (!(out_file->f_mode & FMODE_WRITE))
615                 goto fput_out;
616         retval = -EINVAL;
617         if (!out_file->f_op || !out_file->f_op->sendpage)
618                 goto fput_out;
619         out_inode = out_file->f_dentry->d_inode;
620         retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
621         if (retval)
622                 goto fput_out;
623
624         retval = security_file_permission (out_file, MAY_WRITE);
625         if (retval)
626                 goto fput_out;
627
628         if (!max)
629                 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
630
631         pos = *ppos;
632         retval = -EINVAL;
633         if (unlikely(pos < 0))
634                 goto fput_out;
635         if (unlikely(pos + count > max)) {
636                 retval = -EOVERFLOW;
637                 if (pos >= max)
638                         goto fput_out;
639                 count = max - pos;
640         }
641
642         if ((unsigned long) in_file->f_op->sendfile > PAGE_OFFSET) //kernel
643                 retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
644         else {
645                 CALLDRIVER_PREP5(send, in_file, ppos, count, file_send_actor, out_file)
646                 retval = calldriver((unsigned long) in_file->f_op->sendfile, send_args, send_sizes, 5, current->mm, 0x19, 0);
647         }
648
649         if (*ppos > max)
650                 retval = -EOVERFLOW;
651
652 fput_out:
653         fput_light(out_file, fput_needed_out);
654 fput_in:
655         fput_light(in_file, fput_needed_in);
656 out:
657         return retval;
658 }
659
660 asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
661 {
662         loff_t pos;
663         off_t off;
664         ssize_t ret;
665
666         if (offset) {
667                 if (unlikely(get_user(off, offset)))
668                         return -EFAULT;
669                 pos = off;
670                 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
671                 if (unlikely(put_user(pos, offset)))
672                         return -EFAULT;
673                 return ret;
674         }
675
676         return do_sendfile(out_fd, in_fd, NULL, count, 0);
677 }
678
679 asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
680 {
681         loff_t pos;
682         ssize_t ret;
683
684         if (offset) {
685                 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
686                         return -EFAULT;
687                 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
688                 if (unlikely(put_user(pos, offset)))
689                         return -EFAULT;
690                 return ret;
691         }
692
693         return do_sendfile(out_fd, in_fd, NULL, count, 0);
694 }
Note: See TracBrowser for help on using the browser.