LTP GCOV extension - code coverage report
Current view: directory - fs - read_write.c
Test: kernel.info
Date: 2008-12-15 Instrumented lines: 416
Code covered: 80.5 % Executed lines: 335

       1                 : /*
       2                 :  *  linux/fs/read_write.c
       3                 :  *
       4                 :  *  Copyright (C) 1991, 1992  Linus Torvalds
       5                 :  */
       6                 : 
       7                 : #include <linux/slab.h> 
       8                 : #include <linux/stat.h>
       9                 : #include <linux/fcntl.h>
      10                 : #include <linux/file.h>
      11                 : #include <linux/uio.h>
      12                 : #include <linux/smp_lock.h>
      13                 : #include <linux/fsnotify.h>
      14                 : #include <linux/security.h>
      15                 : #include <linux/module.h>
      16                 : #include <linux/syscalls.h>
      17                 : #include <linux/pagemap.h>
      18                 : #include <linux/splice.h>
      19                 : #include "read_write.h"
      20                 : 
      21                 : #include <asm/uaccess.h>
      22                 : #include <asm/unistd.h>
      23                 : 
      24                 : const struct file_operations generic_ro_fops = {
      25                 :         .llseek         = generic_file_llseek,
      26                 :         .read           = do_sync_read,
      27                 :         .aio_read       = generic_file_aio_read,
      28                 :         .mmap           = generic_file_readonly_mmap,
      29                 :         .splice_read    = generic_file_splice_read,
      30                 : };
      31                 : 
      32                 : EXPORT_SYMBOL(generic_ro_fops);
      33                 : 
      34                 : loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
      35           27261 : {
      36                 :         loff_t retval;
      37           27261 :         struct inode *inode = file->f_mapping->host;
      38                 : 
      39           27261 :         mutex_lock(&inode->i_mutex);
      40           27261 :         switch (origin) {
      41                 :                 case SEEK_END:
      42            4264 :                         offset += inode->i_size;
      43            4264 :                         break;
      44                 :                 case SEEK_CUR:
      45           37303 :                         offset += file->f_pos;
      46                 :         }
      47           27261 :         retval = -EINVAL;
      48           27261 :         if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
      49           27261 :                 if (offset != file->f_pos) {
      50           18940 :                         file->f_pos = offset;
      51           18940 :                         file->f_version = 0;
      52                 :                 }
      53           27261 :                 retval = offset;
      54                 :         }
      55           27261 :         mutex_unlock(&inode->i_mutex);
      56           27261 :         return retval;
      57                 : }
      58                 : 
      59                 : EXPORT_SYMBOL(generic_file_llseek);
      60                 : 
      61                 : loff_t remote_llseek(struct file *file, loff_t offset, int origin)
      62               0 : {
      63                 :         loff_t retval;
      64                 : 
      65               0 :         lock_kernel();
      66               0 :         switch (origin) {
      67                 :                 case SEEK_END:
      68               0 :                         offset += i_size_read(file->f_path.dentry->d_inode);
      69               0 :                         break;
      70                 :                 case SEEK_CUR:
      71               0 :                         offset += file->f_pos;
      72                 :         }
      73               0 :         retval = -EINVAL;
      74               0 :         if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) {
      75               0 :                 if (offset != file->f_pos) {
      76               0 :                         file->f_pos = offset;
      77               0 :                         file->f_version = 0;
      78                 :                 }
      79               0 :                 retval = offset;
      80                 :         }
      81               0 :         unlock_kernel();
      82               0 :         return retval;
      83                 : }
      84                 : EXPORT_SYMBOL(remote_llseek);
      85                 : 
      86                 : loff_t no_llseek(struct file *file, loff_t offset, int origin)
      87           15691 : {
      88           15691 :         return -ESPIPE;
      89                 : }
      90                 : EXPORT_SYMBOL(no_llseek);
      91                 : 
      92                 : loff_t default_llseek(struct file *file, loff_t offset, int origin)
      93               1 : {
      94                 :         loff_t retval;
      95                 : 
      96               1 :         lock_kernel();
      97               1 :         switch (origin) {
      98                 :                 case SEEK_END:
      99               0 :                         offset += i_size_read(file->f_path.dentry->d_inode);
     100               0 :                         break;
     101                 :                 case SEEK_CUR:
     102               1 :                         offset += file->f_pos;
     103                 :         }
     104               1 :         retval = -EINVAL;
     105               1 :         if (offset >= 0) {
     106               1 :                 if (offset != file->f_pos) {
     107               0 :                         file->f_pos = offset;
     108               0 :                         file->f_version = 0;
     109                 :                 }
     110               1 :                 retval = offset;
     111                 :         }
     112               1 :         unlock_kernel();
     113               1 :         return retval;
     114                 : }
     115                 : EXPORT_SYMBOL(default_llseek);
     116                 : 
     117                 : loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
     118           50357 : {
     119                 :         loff_t (*fn)(struct file *, loff_t, int);
     120                 : 
     121           50357 :         fn = no_llseek;
     122           50357 :         if (file->f_mode & FMODE_LSEEK) {
     123           37746 :                 fn = default_llseek;
     124           37746 :                 if (file->f_op && file->f_op->llseek)
     125           37745 :                         fn = file->f_op->llseek;
     126                 :         }
     127           50357 :         return fn(file, offset, origin);
     128                 : }
     129                 : EXPORT_SYMBOL(vfs_llseek);
     130                 : 
     131                 : asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
     132           30905 : {
     133                 :         off_t retval;
     134                 :         struct file * file;
     135                 :         int fput_needed;
     136                 : 
     137           30905 :         retval = -EBADF;
     138           30905 :         file = fget_light(fd, &fput_needed);
     139           30905 :         if (!file)
     140               2 :                 goto bad;
     141                 : 
     142           30903 :         retval = -EINVAL;
     143           30903 :         if (origin <= SEEK_MAX) {
     144           30899 :                 loff_t res = vfs_llseek(file, offset, origin);
     145           30899 :                 retval = res;
     146           30899 :                 if (res != (loff_t)retval)
     147               0 :                         retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
     148                 :         }
     149           30903 :         fput_light(file, fput_needed);
     150           30905 : bad:
     151           30905 :         return retval;
     152                 : }
     153                 : 
     154                 : #ifdef __ARCH_WANT_SYS_LLSEEK
     155                 : asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
     156                 :                            unsigned long offset_low, loff_t __user * result,
     157                 :                            unsigned int origin)
     158           19460 : {
     159                 :         int retval;
     160                 :         struct file * file;
     161                 :         loff_t offset;
     162                 :         int fput_needed;
     163                 : 
     164           19460 :         retval = -EBADF;
     165           19460 :         file = fget_light(fd, &fput_needed);
     166           19460 :         if (!file)
     167               1 :                 goto bad;
     168                 : 
     169           19459 :         retval = -EINVAL;
     170           19459 :         if (origin > SEEK_MAX)
     171               1 :                 goto out_putf;
     172                 : 
     173           19458 :         offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
     174                 :                         origin);
     175                 : 
     176           19458 :         retval = (int)offset;
     177           19458 :         if (offset >= 0) {
     178            3770 :                 retval = -EFAULT;
     179            3770 :                 if (!copy_to_user(result, &offset, sizeof(offset)))
     180            3770 :                         retval = 0;
     181                 :         }
     182           19459 : out_putf:
     183           19459 :         fput_light(file, fput_needed);
     184           19460 : bad:
     185           19460 :         return retval;
     186                 : }
     187                 : #endif
     188                 : 
     189                 : /*
     190                 :  * rw_verify_area doesn't like huge counts. We limit
     191                 :  * them to something that fits in "int" so that others
     192                 :  * won't have to do range checks all the time.
     193                 :  */
     194                 : #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
     195                 : 
     196                 : int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
     197           25842 : {
     198                 :         struct inode *inode;
     199                 :         loff_t pos;
     200           25842 :         int retval = -EINVAL;
     201                 : 
     202           25842 :         inode = file->f_path.dentry->d_inode;
     203           25842 :         if (unlikely((ssize_t) count < 0))
     204               0 :                 return retval;
     205           25842 :         pos = *ppos;
     206           25842 :         if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
     207               2 :                 return retval;
     208                 : 
     209           64532 :         if (unlikely(inode->i_flock && mandatory_lock(inode))) {
     210               0 :                 retval = locks_mandatory_area(
     211                 :                         read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
     212                 :                         inode, file, pos, count);
     213               0 :                 if (retval < 0)
     214               0 :                         return retval;
     215                 :         }
     216           91376 :         retval = security_file_permission(file,
     217                 :                                 read_write == READ ? MAY_READ : MAY_WRITE);
     218           25840 :         if (retval)
     219               0 :                 return retval;
     220           25840 :         return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
     221                 : }
     222                 : 
     223                 : static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
     224               0 : {
     225               0 :         set_current_state(TASK_UNINTERRUPTIBLE);
     226               0 :         if (!kiocbIsKicked(iocb))
     227               0 :                 schedule();
     228                 :         else
     229               0 :                 kiocbClearKicked(iocb);
     230               0 :         __set_current_state(TASK_RUNNING);
     231               0 : }
     232                 : 
     233                 : ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
     234           59970 : {
     235           59970 :         struct iovec iov = { .iov_base = buf, .iov_len = len };
     236                 :         struct kiocb kiocb;
     237                 :         ssize_t ret;
     238                 : 
     239          119940 :         init_sync_kiocb(&kiocb, filp);
     240           59970 :         kiocb.ki_pos = *ppos;
     241           59970 :         kiocb.ki_left = len;
     242                 : 
     243                 :         for (;;) {
     244           59970 :                 ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
     245           59970 :                 if (ret != -EIOCBRETRY)
     246           59970 :                         break;
     247               0 :                 wait_on_retry_sync_kiocb(&kiocb);
     248               0 :         }
     249                 : 
     250           59970 :         if (-EIOCBQUEUED == ret)
     251               0 :                 ret = wait_on_sync_kiocb(&kiocb);
     252           59970 :         *ppos = kiocb.ki_pos;
     253           59970 :         return ret;
     254                 : }
     255                 : 
     256                 : EXPORT_SYMBOL(do_sync_read);
     257                 : 
     258                 : ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
     259           41982 : {
     260                 :         ssize_t ret;
     261                 : 
     262           41982 :         if (!(file->f_mode & FMODE_READ))
     263               2 :                 return -EBADF;
     264           41980 :         if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
     265               0 :                 return -EINVAL;
     266           83960 :         if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
     267               0 :                 return -EFAULT;
     268                 : 
     269           41980 :         ret = rw_verify_area(READ, file, pos, count);
     270          107516 :         if (ret >= 0) {
     271          107516 :                 count = ret;
     272          107516 :                 if (file->f_op->read)
     273           52735 :                         ret = file->f_op->read(file, buf, count, pos);
     274                 :                 else
     275           54781 :                         ret = do_sync_read(file, buf, count, pos);
     276           41978 :                 if (ret > 0) {
     277           42462 :                         fsnotify_access(file->f_path.dentry);
     278                 :                         add_rchar(current, ret);
     279                 :                 }
     280                 :                 inc_syscr(current);
     281                 :         }
     282                 : 
     283           41978 :         return ret;
     284                 : }
     285                 : 
     286                 : EXPORT_SYMBOL(vfs_read);
     287                 : 
     288                 : ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
     289           40920 : {
     290           40920 :         struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
     291                 :         struct kiocb kiocb;
     292                 :         ssize_t ret;
     293                 : 
     294           81840 :         init_sync_kiocb(&kiocb, filp);
     295           40920 :         kiocb.ki_pos = *ppos;
     296           40920 :         kiocb.ki_left = len;
     297                 : 
     298                 :         for (;;) {
     299           40920 :                 ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
     300           40920 :                 if (ret != -EIOCBRETRY)
     301           40920 :                         break;
     302               0 :                 wait_on_retry_sync_kiocb(&kiocb);
     303               0 :         }
     304                 : 
     305           40920 :         if (-EIOCBQUEUED == ret)
     306               0 :                 ret = wait_on_sync_kiocb(&kiocb);
     307           40920 :         *ppos = kiocb.ki_pos;
     308           40920 :         return ret;
     309                 : }
     310                 : 
     311                 : EXPORT_SYMBOL(do_sync_write);
     312                 : 
     313                 : ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
     314           31057 : {
     315                 :         ssize_t ret;
     316                 : 
     317           31057 :         if (!(file->f_mode & FMODE_WRITE))
     318              18 :                 return -EBADF;
     319           31039 :         if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
     320               0 :                 return -EINVAL;
     321           62078 :         if (unlikely(!access_ok(VERIFY_READ, buf, count)))
     322               0 :                 return -EFAULT;
     323                 : 
     324           31039 :         ret = rw_verify_area(WRITE, file, pos, count);
     325           31039 :         if (ret >= 0) {
     326           31039 :                 count = ret;
     327           31039 :                 if (file->f_op->write)
     328           30021 :                         ret = file->f_op->write(file, buf, count, pos);
     329                 :                 else
     330            1018 :                         ret = do_sync_write(file, buf, count, pos);
     331           31040 :                 if (ret > 0) {
     332           30989 :                         fsnotify_modify(file->f_path.dentry);
     333                 :                         add_wchar(current, ret);
     334                 :                 }
     335                 :                 inc_syscw(current);
     336                 :         }
     337                 : 
     338           31040 :         return ret;
     339                 : }
     340                 : 
     341                 : EXPORT_SYMBOL(vfs_write);
     342                 : 
     343                 : static inline loff_t file_pos_read(struct file *file)
     344                 : {
     345           49342 :         return file->f_pos;
     346                 : }
     347                 : 
     348                 : static inline void file_pos_write(struct file *file, loff_t pos)
     349                 : {
     350           49341 :         file->f_pos = pos;
     351                 : }
     352                 : 
     353                 : asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
     354              17 : {
     355                 :         struct file *file;
     356              17 :         ssize_t ret = -EBADF;
     357                 :         int fput_needed;
     358                 : 
     359              17 :         file = fget_light(fd, &fput_needed);
     360              17 :         if (file) {
     361              15 :                 loff_t pos = file_pos_read(file);
     362              15 :                 ret = vfs_read(file, buf, count, &pos);
     363              13 :                 file_pos_write(file, pos);
     364              13 :                 fput_light(file, fput_needed);
     365                 :         }
     366                 : 
     367              15 :         return ret;
     368                 : }
     369                 : 
     370                 : asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
     371           31044 : {
     372                 :         struct file *file;
     373           31044 :         ssize_t ret = -EBADF;
     374                 :         int fput_needed;
     375                 : 
     376           31044 :         file = fget_light(fd, &fput_needed);
     377           31044 :         if (file) {
     378           31043 :                 loff_t pos = file_pos_read(file);
     379           31043 :                 ret = vfs_write(file, buf, count, &pos);
     380           31044 :                 file_pos_write(file, pos);
     381           31044 :                 fput_light(file, fput_needed);
     382                 :         }
     383                 : 
     384           31045 :         return ret;
     385                 : }
     386                 : 
     387                 : asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
     388                 :                              size_t count, loff_t pos)
     389              12 : {
     390                 :         struct file *file;
     391              12 :         ssize_t ret = -EBADF;
     392                 :         int fput_needed;
     393                 : 
     394              12 :         if (pos < 0)
     395               2 :                 return -EINVAL;
     396                 : 
     397              10 :         file = fget_light(fd, &fput_needed);
     398              10 :         if (file) {
     399              10 :                 ret = -ESPIPE;
     400              10 :                 if (file->f_mode & FMODE_PREAD)
     401               8 :                         ret = vfs_read(file, buf, count, &pos);
     402              10 :                 fput_light(file, fput_needed);
     403                 :         }
     404                 : 
     405              10 :         return ret;
     406                 : }
     407                 : 
     408                 : asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
     409                 :                               size_t count, loff_t pos)
     410              17 : {
     411                 :         struct file *file;
     412              17 :         ssize_t ret = -EBADF;
     413                 :         int fput_needed;
     414                 : 
     415              17 :         if (pos < 0)
     416               1 :                 return -EINVAL;
     417                 : 
     418              16 :         file = fget_light(fd, &fput_needed);
     419              16 :         if (file) {
     420              15 :                 ret = -ESPIPE;
     421              15 :                 if (file->f_mode & FMODE_PWRITE)  
     422              14 :                         ret = vfs_write(file, buf, count, &pos);
     423              15 :                 fput_light(file, fput_needed);
     424                 :         }
     425                 : 
     426              16 :         return ret;
     427                 : }
     428                 : 
     429                 : /*
     430                 :  * Reduce an iovec's length in-place.  Return the resulting number of segments
     431                 :  */
     432                 : unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
     433               0 : {
     434               0 :         unsigned long seg = 0;
     435               0 :         size_t len = 0;
     436                 : 
     437               0 :         while (seg < nr_segs) {
     438               0 :                 seg++;
     439               0 :                 if (len + iov->iov_len >= to) {
     440               0 :                         iov->iov_len = to - len;
     441               0 :                         break;
     442                 :                 }
     443               0 :                 len += iov->iov_len;
     444               0 :                 iov++;
     445                 :         }
     446               0 :         return seg;
     447                 : }
     448                 : EXPORT_SYMBOL(iov_shorten);
     449                 : 
     450                 : ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
     451                 :                 unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
     452           18255 : {
     453                 :         struct kiocb kiocb;
     454                 :         ssize_t ret;
     455                 : 
     456           36510 :         init_sync_kiocb(&kiocb, filp);
     457           18255 :         kiocb.ki_pos = *ppos;
     458           18255 :         kiocb.ki_left = len;
     459           18255 :         kiocb.ki_nbytes = len;
     460                 : 
     461                 :         for (;;) {
     462           18255 :                 ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
     463           18255 :                 if (ret != -EIOCBRETRY)
     464           18255 :                         break;
     465               0 :                 wait_on_retry_sync_kiocb(&kiocb);
     466               0 :         }
     467                 : 
     468           18255 :         if (ret == -EIOCBQUEUED)
     469               0 :                 ret = wait_on_sync_kiocb(&kiocb);
     470           18255 :         *ppos = kiocb.ki_pos;
     471           18255 :         return ret;
     472                 : }
     473                 : 
     474                 : /* Do it by hand, with file-ops */
     475                 : ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
     476                 :                 unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
     477              23 : {
     478              23 :         struct iovec *vector = iov;
     479              23 :         ssize_t ret = 0;
     480                 : 
     481             136 :         while (nr_segs > 0) {
     482                 :                 void __user *base;
     483                 :                 size_t len;
     484                 :                 ssize_t nr;
     485                 : 
     486              91 :                 base = vector->iov_base;
     487              91 :                 len = vector->iov_len;
     488              91 :                 vector++;
     489              91 :                 nr_segs--;
     490                 : 
     491              91 :                 nr = fn(filp, base, len, ppos);
     492                 : 
     493              91 :                 if (nr < 0) {
     494               1 :                         if (!ret)
     495               1 :                                 ret = nr;
     496                 :                         break;
     497                 :                 }
     498              90 :                 ret += nr;
     499              90 :                 if (nr != len)
     500               0 :                         break;
     501                 :         }
     502                 : 
     503              23 :         return ret;
     504                 : }
     505                 : 
     506                 : /* A write operation does a read from user space and vice versa */
     507                 : #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
     508                 : 
     509                 : ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
     510                 :                               unsigned long nr_segs, unsigned long fast_segs,
     511                 :                               struct iovec *fast_pointer,
     512                 :                               struct iovec **ret_pointer)
     513           18284 :   {
     514                 :         unsigned long seg;
     515                 :         ssize_t ret;
     516           18284 :         struct iovec *iov = fast_pointer;
     517                 : 
     518                 :         /*
     519                 :          * SuS says "The readv() function *may* fail if the iovcnt argument
     520                 :          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
     521                 :          * traditionally returned zero for zero segments, so...
     522                 :          */
     523           18284 :         if (nr_segs == 0) {
     524               2 :                 ret = 0;
     525               2 :                 goto out;
     526                 :         }
     527                 : 
     528                 :         /*
     529                 :          * First get the "struct iovec" from user memory and
     530                 :          * verify all the pointers
     531                 :          */
     532           18282 :         if (nr_segs > UIO_MAXIOV) {
     533               2 :                 ret = -EINVAL;
     534               2 :                 goto out;
     535                 :         }
     536           18280 :         if (nr_segs > fast_segs) {
     537              12 :                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
     538               6 :                 if (iov == NULL) {
     539               0 :                         ret = -ENOMEM;
     540               0 :                         goto out;
     541                 :                 }
     542                 :         }
     543           18280 :         if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
     544               0 :                 ret = -EFAULT;
     545               0 :                 goto out;
     546                 :         }
     547                 : 
     548                 :         /*
     549                 :          * According to the Single Unix Specification we should return EINVAL
     550                 :          * if an element length is < 0 when cast to ssize_t or if the
     551                 :          * total length would overflow the ssize_t return value of the
     552                 :          * system call.
     553                 :          */
     554           18280 :         ret = 0;
     555           30504 :         for (seg = 0; seg < nr_segs; seg++) {
     556           12226 :                 void __user *buf = iov[seg].iov_base;
     557           12226 :                 ssize_t len = (ssize_t)iov[seg].iov_len;
     558                 : 
     559                 :                 /* see if we we're about to use an invalid len or if
     560                 :                  * it's about to overflow ssize_t */
     561           12226 :                 if (len < 0 || (ret + len < ret)) {
     562               2 :                         ret = -EINVAL;
     563               2 :                         goto out;
     564                 :                 }
     565           12224 :                 if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
     566               0 :                         ret = -EFAULT;
     567               0 :                         goto out;
     568                 :                 }
     569                 : 
     570           12224 :                 ret += len;
     571                 :         }
     572           18284 : out:
     573           18284 :         *ret_pointer = iov;
     574           18284 :         return ret;
     575                 : }
     576                 : 
     577                 : static ssize_t do_readv_writev(int type, struct file *file,
     578                 :                                const struct iovec __user * uvector,
     579                 :                                unsigned long nr_segs, loff_t *pos)
     580           18284 : {
     581                 :         size_t tot_len;
     582                 :         struct iovec iovstack[UIO_FASTIOV];
     583           18284 :         struct iovec *iov = iovstack;
     584                 :         ssize_t ret;
     585                 :         io_fn_t fn;
     586                 :         iov_fn_t fnv;
     587                 : 
     588           18284 :         if (!file->f_op) {
     589               0 :                 ret = -EINVAL;
     590               0 :                 goto out;
     591                 :         }
     592                 : 
     593           18284 :         ret = rw_copy_check_uvector(type, uvector, nr_segs,
     594                 :                         ARRAY_SIZE(iovstack), iovstack, &iov);
     595           18284 :         if (ret <= 0)
     596               6 :                 goto out;
     597                 : 
     598           18278 :         tot_len = ret;
     599           18278 :         ret = rw_verify_area(type, file, pos, tot_len);
     600           18278 :         if (ret < 0)
     601               0 :                 goto out;
     602                 : 
     603           18278 :         fnv = NULL;
     604           18278 :         if (type == READ) {
     605               3 :                 fn = file->f_op->read;
     606               3 :                 fnv = file->f_op->aio_read;
     607                 :         } else {
     608           18275 :                 fn = (io_fn_t)file->f_op->write;
     609           18275 :                 fnv = file->f_op->aio_write;
     610                 :         }
     611                 : 
     612           18278 :         if (fnv)
     613           18255 :                 ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
     614                 :                                                 pos, fnv);
     615                 :         else
     616              23 :                 ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
     617                 : 
     618           18284 : out:
     619           18284 :         if (iov != iovstack)
     620               6 :                 kfree(iov);
     621           18284 :         if ((ret + (type == READ)) > 0) {
     622           17870 :                 if (type == READ)
     623               2 :                         fsnotify_access(file->f_path.dentry);
     624                 :                 else
     625           17868 :                         fsnotify_modify(file->f_path.dentry);
     626                 :         }
     627           18284 :         return ret;
     628                 : }
     629                 : 
     630                 : ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
     631                 :                   unsigned long vlen, loff_t *pos)
     632               6 : {
     633               6 :         if (!(file->f_mode & FMODE_READ))
     634               0 :                 return -EBADF;
     635               6 :         if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
     636               0 :                 return -EINVAL;
     637                 : 
     638               6 :         return do_readv_writev(READ, file, vec, vlen, pos);
     639                 : }
     640                 : 
     641                 : EXPORT_SYMBOL(vfs_readv);
     642                 : 
     643                 : ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
     644                 :                    unsigned long vlen, loff_t *pos)
     645           18278 : {
     646           18278 :         if (!(file->f_mode & FMODE_WRITE))
     647               0 :                 return -EBADF;
     648           18278 :         if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
     649               0 :                 return -EINVAL;
     650                 : 
     651           18278 :         return do_readv_writev(WRITE, file, vec, vlen, pos);
     652                 : }
     653                 : 
     654                 : EXPORT_SYMBOL(vfs_writev);
     655                 : 
     656                 : asmlinkage ssize_t
     657                 : sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
     658               7 : {
     659                 :         struct file *file;
     660               7 :         ssize_t ret = -EBADF;
     661                 :         int fput_needed;
     662                 : 
     663               7 :         file = fget_light(fd, &fput_needed);
     664               7 :         if (file) {
     665               6 :                 loff_t pos = file_pos_read(file);
     666               6 :                 ret = vfs_readv(file, vec, vlen, &pos);
     667               6 :                 file_pos_write(file, pos);
     668               6 :                 fput_light(file, fput_needed);
     669                 :         }
     670                 : 
     671               7 :         if (ret > 0)
     672                 :                 add_rchar(current, ret);
     673                 :         inc_syscr(current);
     674               7 :         return ret;
     675                 : }
     676                 : 
     677                 : asmlinkage ssize_t
     678                 : sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
     679           18279 : {
     680                 :         struct file *file;
     681           18279 :         ssize_t ret = -EBADF;
     682                 :         int fput_needed;
     683                 : 
     684           18279 :         file = fget_light(fd, &fput_needed);
     685           18279 :         if (file) {
     686           18278 :                 loff_t pos = file_pos_read(file);
     687           18278 :                 ret = vfs_writev(file, vec, vlen, &pos);
     688           18278 :                 file_pos_write(file, pos);
     689           18278 :                 fput_light(file, fput_needed);
     690                 :         }
     691                 : 
     692           18279 :         if (ret > 0)
     693                 :                 add_wchar(current, ret);
     694                 :         inc_syscw(current);
     695           18279 :         return ret;
     696                 : }
     697                 : 
     698                 : static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
     699                 :                            size_t count, loff_t max)
     700              26 : {
     701                 :         struct file * in_file, * out_file;
     702                 :         struct inode * in_inode, * out_inode;
     703                 :         loff_t pos;
     704                 :         ssize_t retval;
     705                 :         int fput_needed_in, fput_needed_out, fl;
     706                 : 
     707                 :         /*
     708                 :          * Get input file, and verify that it is ok..
     709                 :          */
     710              26 :         retval = -EBADF;
     711              26 :         in_file = fget_light(in_fd, &fput_needed_in);
     712              26 :         if (!in_file)
     713               6 :                 goto out;
     714              20 :         if (!(in_file->f_mode & FMODE_READ))
     715               0 :                 goto fput_in;
     716              20 :         retval = -EINVAL;
     717              20 :         in_inode = in_file->f_path.dentry->d_inode;
     718              20 :         if (!in_inode)
     719               0 :                 goto fput_in;
     720              20 :         if (!in_file->f_op || !in_file->f_op->splice_read)
     721                 :                 goto fput_in;
     722              20 :         retval = -ESPIPE;
     723              20 :         if (!ppos)
     724               4 :                 ppos = &in_file->f_pos;
     725                 :         else
     726              16 :                 if (!(in_file->f_mode & FMODE_PREAD))
     727               0 :                         goto fput_in;
     728              20 :         retval = rw_verify_area(READ, in_file, ppos, count);
     729              20 :         if (retval < 0)
     730               2 :                 goto fput_in;
     731              18 :         count = retval;
     732                 : 
     733                 :         /*
     734                 :          * Get output file, and verify that it is ok..
     735                 :          */
     736              18 :         retval = -EBADF;
     737              18 :         out_file = fget_light(out_fd, &fput_needed_out);
     738              18 :         if (!out_file)
     739               0 :                 goto fput_in;
     740              18 :         if (!(out_file->f_mode & FMODE_WRITE))
     741               0 :                 goto fput_out;
     742              18 :         retval = -EINVAL;
     743              18 :         if (!out_file->f_op || !out_file->f_op->sendpage)
     744                 :                 goto fput_out;
     745              18 :         out_inode = out_file->f_path.dentry->d_inode;
     746              18 :         retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
     747              18 :         if (retval < 0)
     748               0 :                 goto fput_out;
     749              18 :         count = retval;
     750                 : 
     751              18 :         if (!max)
     752              11 :                 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
     753                 : 
     754              18 :         pos = *ppos;
     755              18 :         retval = -EINVAL;
     756              18 :         if (unlikely(pos < 0))
     757               0 :                 goto fput_out;
     758              18 :         if (unlikely(pos + count > max)) {
     759               0 :                 retval = -EOVERFLOW;
     760               0 :                 if (pos >= max)
     761               0 :                         goto fput_out;
     762               0 :                 count = max - pos;
     763                 :         }
     764                 : 
     765              18 :         fl = 0;
     766                 : #if 0
     767                 :         /*
     768                 :          * We need to debate whether we can enable this or not. The
     769                 :          * man page documents EAGAIN return for the output at least,
     770                 :          * and the application is arguably buggy if it doesn't expect
     771                 :          * EAGAIN on a non-blocking file descriptor.
     772                 :          */
     773                 :         if (in_file->f_flags & O_NONBLOCK)
     774                 :                 fl = SPLICE_F_NONBLOCK;
     775                 : #endif
     776              18 :         retval = do_splice_direct(in_file, ppos, out_file, count, fl);
     777                 : 
     778              18 :         if (retval > 0) {
     779                 :                 add_rchar(current, retval);
     780                 :                 add_wchar(current, retval);
     781                 :         }
     782                 : 
     783                 :         inc_syscr(current);
     784                 :         inc_syscw(current);
     785              18 :         if (*ppos > max)
     786               0 :                 retval = -EOVERFLOW;
     787                 : 
     788              18 : fput_out:
     789              18 :         fput_light(out_file, fput_needed_out);
     790              20 : fput_in:
     791              20 :         fput_light(in_file, fput_needed_in);
     792              26 : out:
     793              26 :         return retval;
     794                 : }
     795                 : 
     796                 : asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
     797              15 : {
     798                 :         loff_t pos;
     799                 :         off_t off;
     800                 :         ssize_t ret;
     801                 : 
     802              15 :         if (offset) {
     803              10 :                 if (unlikely(get_user(off, offset)))
     804               2 :                         return -EFAULT;
     805               8 :                 pos = off;
     806               8 :                 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
     807               8 :                 if (unlikely(put_user(pos, offset)))
     808               3 :                         return -EFAULT;
     809               5 :                 return ret;
     810                 :         }
     811                 : 
     812               5 :         return do_sendfile(out_fd, in_fd, NULL, count, 0);
     813                 : }
     814                 : 
     815                 : asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
     816              15 : {
     817                 :         loff_t pos;
     818                 :         ssize_t ret;
     819                 : 
     820              15 :         if (offset) {
     821              10 :                 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
     822               2 :                         return -EFAULT;
     823               8 :                 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
     824               8 :                 if (unlikely(put_user(pos, offset)))
     825               3 :                         return -EFAULT;
     826               5 :                 return ret;
     827                 :         }
     828                 : 
     829               5 :         return do_sendfile(out_fd, in_fd, NULL, count, 0);
     830                 : }

Generated by: LTP GCOV extension version 1.6