The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/read_write.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/read_write.c
    3  *
    4  *  Copyright (C) 1991, 1992  Linus Torvalds
    5  *  Minor pieces Copyright (C) 2002 Red Hat Inc, All Rights Reserved
    6  *
    7  *  This program is free software; you can redistribute it and/or modify
    8  *  it under the terms of the GNU General Public License as published by
    9  *  the Free Software Foundation; either version 2 of the License, or
   10  *  (at your option) any later version.
   11  *
   12  *  This program is distributed in the hope that it will be useful,
   13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  *  GNU General Public License for more details.
   16  *
   17  *  You should have received a copy of the GNU General Public License
   18  *  along with this program; if not, write to the Free Software
   19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20  */
   21 
   22 #include <linux/slab.h> 
   23 #include <linux/stat.h>
   24 #include <linux/fcntl.h>
   25 #include <linux/file.h>
   26 #include <linux/uio.h>
   27 #include <linux/smp_lock.h>
   28 #include <linux/dnotify.h>
   29 
   30 #include <asm/uaccess.h>
   31 
   32 struct file_operations generic_ro_fops = {
   33         llseek:         generic_file_llseek,
   34         read:           generic_file_read,
   35         mmap:           generic_file_mmap,
   36 };
   37 
   38 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
   39 {
   40         return -EISDIR;
   41 }
   42 
   43 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
   44 {
   45         long long retval;
   46 
   47         switch (origin) {
   48                 case 2:
   49                         offset += file->f_dentry->d_inode->i_size;
   50                         break;
   51                 case 1:
   52                         offset += file->f_pos;
   53         }
   54         retval = -EINVAL;
   55         if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
   56                 if (offset != file->f_pos) {
   57                         file->f_pos = offset;
   58                         file->f_reada = 0;
   59                         file->f_version = ++event;
   60                 }
   61                 retval = offset;
   62         }
   63         return retval;
   64 }
   65 
   66 loff_t no_llseek(struct file *file, loff_t offset, int origin)
   67 {
   68         return -ESPIPE;
   69 }
   70 
   71 loff_t default_llseek(struct file *file, loff_t offset, int origin)
   72 {
   73         long long retval;
   74 
   75         switch (origin) {
   76                 case 2:
   77                         offset += file->f_dentry->d_inode->i_size;
   78                         break;
   79                 case 1:
   80                         offset += file->f_pos;
   81         }
   82         retval = -EINVAL;
   83         if (offset >= 0) {
   84                 if (offset != file->f_pos) {
   85                         file->f_pos = offset;
   86                         file->f_reada = 0;
   87                         file->f_version = ++event;
   88                 }
   89                 retval = offset;
   90         }
   91         return retval;
   92 }
   93 
   94 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
   95 {
   96         loff_t (*fn)(struct file *, loff_t, int);
   97         loff_t retval;
   98 
   99         fn = default_llseek;
  100         if (file->f_op && file->f_op->llseek)
  101                 fn = file->f_op->llseek;
  102         lock_kernel();
  103         retval = fn(file, offset, origin);
  104         unlock_kernel();
  105         return retval;
  106 }
  107 
  108 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
  109 {
  110         off_t retval;
  111         struct file * file;
  112 
  113         retval = -EBADF;
  114         file = fget(fd);
  115         if (!file)
  116                 goto bad;
  117         retval = -EINVAL;
  118         if (origin <= 2) {
  119                 loff_t res = llseek(file, offset, origin);
  120                 retval = res;
  121                 if (res != (loff_t)retval)
  122                         retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
  123         }
  124         fput(file);
  125 bad:
  126         return retval;
  127 }
  128 
  129 #if !defined(__alpha__)
  130 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
  131                            unsigned long offset_low, loff_t * result,
  132                            unsigned int origin)
  133 {
  134         int retval;
  135         struct file * file;
  136         loff_t offset;
  137 
  138         retval = -EBADF;
  139         file = fget(fd);
  140         if (!file)
  141                 goto bad;
  142         retval = -EINVAL;
  143         if (origin > 2)
  144                 goto out_putf;
  145 
  146         offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
  147                         origin);
  148 
  149         retval = (int)offset;
  150         if (offset >= 0) {
  151                 retval = -EFAULT;
  152                 if (!copy_to_user(result, &offset, sizeof(offset)))
  153                         retval = 0;
  154         }
  155 out_putf:
  156         fput(file);
  157 bad:
  158         return retval;
  159 }
  160 #endif
  161 
  162 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
  163 {
  164         ssize_t ret;
  165         struct file * file;
  166 
  167         ret = -EBADF;
  168         file = fget(fd);
  169         if (file) {
  170                 if (file->f_mode & FMODE_READ) {
  171                         ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
  172                                                 file, file->f_pos, count);
  173                         if (!ret) {
  174                                 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
  175                                 ret = -EINVAL;
  176                                 if (file->f_op && (read = file->f_op->read) != NULL)
  177                                         ret = read(file, buf, count, &file->f_pos);
  178                         }
  179                 }
  180                 if (ret > 0)
  181                         dnotify_parent(file->f_dentry, DN_ACCESS);
  182                 fput(file);
  183         }
  184         return ret;
  185 }
  186 
  187 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
  188 {
  189         ssize_t ret;
  190         struct file * file;
  191 
  192         ret = -EBADF;
  193         file = fget(fd);
  194         if (file) {
  195                 if (file->f_mode & FMODE_WRITE) {
  196                         struct inode *inode = file->f_dentry->d_inode;
  197                         ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
  198                                 file->f_pos, count);
  199                         if (!ret) {
  200                                 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
  201                                 ret = -EINVAL;
  202                                 if (file->f_op && (write = file->f_op->write) != NULL)
  203                                         ret = write(file, buf, count, &file->f_pos);
  204                         }
  205                 }
  206                 if (ret > 0)
  207                         dnotify_parent(file->f_dentry, DN_MODIFY);
  208                 fput(file);
  209         }
  210         return ret;
  211 }
  212 
  213 
  214 static ssize_t do_readv_writev(int type, struct file *file,
  215                                const struct iovec * vector,
  216                                unsigned long count)
  217 {
  218         typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
  219         typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
  220 
  221         size_t tot_len;
  222         struct iovec iovstack[UIO_FASTIOV];
  223         struct iovec *iov=iovstack;
  224         ssize_t ret, i;
  225         io_fn_t fn;
  226         iov_fn_t fnv;
  227         struct inode *inode;
  228 
  229         /*
  230          * First get the "struct iovec" from user memory and
  231          * verify all the pointers
  232          */
  233         ret = 0;
  234         if (!count)
  235                 goto out_nofree;
  236         ret = -EINVAL;
  237         if (count > UIO_MAXIOV)
  238                 goto out_nofree;
  239         if (!file->f_op)
  240                 goto out_nofree;
  241         if (count > UIO_FASTIOV) {
  242                 ret = -ENOMEM;
  243                 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
  244                 if (!iov)
  245                         goto out_nofree;
  246         }
  247         ret = -EFAULT;
  248         if (copy_from_user(iov, vector, count*sizeof(*vector)))
  249                 goto out;
  250 
  251         /*
  252          * Single unix specification:
  253          * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
  254          * The total length is fitting an ssize_t
  255          *
  256          * Be careful here because iov_len is a size_t not an ssize_t
  257          */
  258          
  259         tot_len = 0;
  260         ret = -EINVAL;
  261         for (i = 0 ; i < count ; i++) {
  262                 ssize_t len = (ssize_t) iov[i].iov_len;
  263                 if (len < 0)    /* size_t not fitting an ssize_t .. */
  264                         goto out;
  265                 tot_len += len;
  266                 /* We must do this work unsigned - signed overflow is
  267                    undefined and gcc 3.2 now uses that fact sometimes... 
  268                    
  269                    FIXME: put in a proper limits.h for each platform */
  270 #if BITS_PER_LONG==64
  271                 if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
  272 #else
  273                 if (tot_len > 0x7FFFFFFFUL)
  274 #endif          
  275                         goto out;
  276         }
  277 
  278         inode = file->f_dentry->d_inode;
  279         /* VERIFY_WRITE actually means a read, as we write to user space */
  280         ret = locks_verify_area((type == VERIFY_WRITE
  281                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
  282                                 inode, file, file->f_pos, tot_len);
  283         if (ret) goto out;
  284 
  285         fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
  286         if (fnv) {
  287                 ret = fnv(file, iov, count, &file->f_pos);
  288                 goto out;
  289         }
  290 
  291         /* VERIFY_WRITE actually means a read, as we write to user space */
  292         fn = (type == VERIFY_WRITE ? file->f_op->read :
  293               (io_fn_t) file->f_op->write);
  294 
  295         ret = 0;
  296         vector = iov;
  297         while (count > 0) {
  298                 void * base;
  299                 size_t len;
  300                 ssize_t nr;
  301 
  302                 base = vector->iov_base;
  303                 len = vector->iov_len;
  304                 vector++;
  305                 count--;
  306 
  307                 nr = fn(file, base, len, &file->f_pos);
  308 
  309                 if (nr < 0) {
  310                         if (!ret) ret = nr;
  311                         break;
  312                 }
  313                 ret += nr;
  314                 if (nr != len)
  315                         break;
  316         }
  317 
  318 out:
  319         if (iov != iovstack)
  320                 kfree(iov);
  321 out_nofree:
  322         /* VERIFY_WRITE actually means a read, as we write to user space */
  323         if ((ret + (type == VERIFY_WRITE)) > 0)
  324                 dnotify_parent(file->f_dentry,
  325                         (type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
  326         return ret;
  327 }
  328 
  329 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
  330                              unsigned long count)
  331 {
  332         struct file * file;
  333         ssize_t ret;
  334 
  335 
  336         ret = -EBADF;
  337         file = fget(fd);
  338         if (!file)
  339                 goto bad_file;
  340         if (file->f_op && (file->f_mode & FMODE_READ) &&
  341             (file->f_op->readv || file->f_op->read))
  342                 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
  343         fput(file);
  344 
  345 bad_file:
  346         return ret;
  347 }
  348 
  349 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
  350                               unsigned long count)
  351 {
  352         struct file * file;
  353         ssize_t ret;
  354 
  355 
  356         ret = -EBADF;
  357         file = fget(fd);
  358         if (!file)
  359                 goto bad_file;
  360         if (file->f_op && (file->f_mode & FMODE_WRITE) &&
  361             (file->f_op->writev || file->f_op->write))
  362                 ret = do_readv_writev(VERIFY_READ, file, vector, count);
  363         fput(file);
  364 
  365 bad_file:
  366         return ret;
  367 }
  368 
  369 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
  370    lseek back to original location.  They fail just like lseek does on
  371    non-seekable files.  */
  372 
  373 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
  374                              size_t count, loff_t pos)
  375 {
  376         ssize_t ret;
  377         struct file * file;
  378         ssize_t (*read)(struct file *, char *, size_t, loff_t *);
  379 
  380         ret = -EBADF;
  381         file = fget(fd);
  382         if (!file)
  383                 goto bad_file;
  384         if (!(file->f_mode & FMODE_READ))
  385                 goto out;
  386         ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
  387                                 file, pos, count);
  388         if (ret)
  389                 goto out;
  390         ret = -EINVAL;
  391         if (!file->f_op || !(read = file->f_op->read))
  392                 goto out;
  393         if (pos < 0)
  394                 goto out;
  395         ret = read(file, buf, count, &pos);
  396         if (ret > 0)
  397                 dnotify_parent(file->f_dentry, DN_ACCESS);
  398 out:
  399         fput(file);
  400 bad_file:
  401         return ret;
  402 }
  403 
  404 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
  405                               size_t count, loff_t pos)
  406 {
  407         ssize_t ret;
  408         struct file * file;
  409         ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
  410 
  411         ret = -EBADF;
  412         file = fget(fd);
  413         if (!file)
  414                 goto bad_file;
  415         if (!(file->f_mode & FMODE_WRITE))
  416                 goto out;
  417         ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
  418                                 file, pos, count);
  419         if (ret)
  420                 goto out;
  421         ret = -EINVAL;
  422         if (!file->f_op || !(write = file->f_op->write))
  423                 goto out;
  424         if (pos < 0)
  425                 goto out;
  426 
  427         ret = write(file, buf, count, &pos);
  428         if (ret > 0)
  429                 dnotify_parent(file->f_dentry, DN_MODIFY);
  430 out:
  431         fput(file);
  432 bad_file:
  433         return ret;
  434 }

Cache object: e6e138c3dcd6749fc2c8a33858c40a30


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.