~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/read_write.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp