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/kern/vfs_vnops.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  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  * (c) UNIX System Laboratories, Inc.
    5  * All or some portions of this file are derived from material licensed
    6  * to the University of California by American Telephone and Telegraph
    7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    8  * the permission of UNIX System Laboratories, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *
   38  *      @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
   39  * $FreeBSD$
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/file.h>
   46 #include <sys/stat.h>
   47 #include <sys/proc.h>
   48 #include <sys/mount.h>
   49 #include <sys/namei.h>
   50 #include <sys/vnode.h>
   51 #include <sys/filio.h>
   52 #include <sys/ttycom.h>
   53 
   54 static int vn_closefile __P((struct file *fp, struct proc *p));
   55 static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data, 
   56                 struct proc *p));
   57 static int vn_read __P((struct file *fp, struct uio *uio, 
   58                 struct ucred *cred, int flags));
   59 static int vn_poll __P((struct file *fp, int events, struct ucred *cred,
   60                 struct proc *p));
   61 static int vn_write __P((struct file *fp, struct uio *uio, 
   62                 struct ucred *cred, int flags));
   63 
   64 struct  fileops vnops =
   65         { vn_read, vn_write, vn_ioctl, vn_poll, vn_closefile };
   66 
   67 /*
   68  * Common code for vnode open operations.
   69  * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
   70  */
   71 int
   72 vn_open(ndp, fmode, cmode)
   73         register struct nameidata *ndp;
   74         int fmode, cmode;
   75 {
   76         register struct vnode *vp;
   77         register struct proc *p = ndp->ni_cnd.cn_proc;
   78         register struct ucred *cred = p->p_ucred;
   79         struct vattr vat;
   80         struct vattr *vap = &vat;
   81         int mode, error;
   82 
   83         if (fmode & O_CREAT) {
   84                 ndp->ni_cnd.cn_nameiop = CREATE;
   85                 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
   86                 if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
   87                         ndp->ni_cnd.cn_flags |= FOLLOW;
   88                 error = namei(ndp);
   89                 if (error)
   90                         return (error);
   91                 if (ndp->ni_vp == NULL) {
   92                         VATTR_NULL(vap);
   93                         vap->va_type = VREG;
   94                         vap->va_mode = cmode;
   95                         if (fmode & O_EXCL)
   96                                 vap->va_vaflags |= VA_EXCLUSIVE;
   97                         VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
   98                         error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
   99                                            &ndp->ni_cnd, vap);
  100                         vput(ndp->ni_dvp);
  101                         if (error)
  102                                 return (error);
  103                         ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "create");
  104                         ASSERT_VOP_LOCKED(ndp->ni_vp, "create");
  105                         fmode &= ~O_TRUNC;
  106                         vp = ndp->ni_vp;
  107                 } else {
  108                         VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
  109                         if (ndp->ni_dvp == ndp->ni_vp)
  110                                 vrele(ndp->ni_dvp);
  111                         else
  112                                 vput(ndp->ni_dvp);
  113                         ndp->ni_dvp = NULL;
  114                         vp = ndp->ni_vp;
  115                         if (fmode & O_EXCL) {
  116                                 error = EEXIST;
  117                                 goto bad;
  118                         }
  119                         fmode &= ~O_CREAT;
  120                 }
  121         } else {
  122                 ndp->ni_cnd.cn_nameiop = LOOKUP;
  123                 ndp->ni_cnd.cn_flags =
  124                     ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF;
  125                 error = namei(ndp);
  126                 if (error)
  127                         return (error);
  128                 vp = ndp->ni_vp;
  129         }
  130         if (vp->v_type == VLNK) {
  131                 error = EMLINK;
  132                 goto bad;
  133         }
  134         if (vp->v_type == VSOCK) {
  135                 error = EOPNOTSUPP;
  136                 goto bad;
  137         }
  138         if ((fmode & O_CREAT) == 0) {
  139                 mode = 0;
  140                 if (fmode & (FWRITE | O_TRUNC)) {
  141                         if (vp->v_type == VDIR) {
  142                                 error = EISDIR;
  143                                 goto bad;
  144                         }
  145                         error = vn_writechk(vp);
  146                         if (error)
  147                                 goto bad;
  148                         mode |= VWRITE;
  149                 }
  150                 if (fmode & FREAD)
  151                         mode |= VREAD;
  152                 if (mode) {
  153                         error = VOP_ACCESS(vp, mode, cred, p);
  154                         if (error)
  155                                 goto bad;
  156                 }
  157         }
  158         if (fmode & O_TRUNC) {
  159                 VOP_UNLOCK(vp, 0, p);                           /* XXX */
  160                 VOP_LEASE(vp, p, cred, LEASE_WRITE);
  161                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);        /* XXX */
  162                 VATTR_NULL(vap);
  163                 vap->va_size = 0;
  164                 error = VOP_SETATTR(vp, vap, cred, p);
  165                 if (error)
  166                         goto bad;
  167         }
  168         error = VOP_OPEN(vp, fmode, cred, p);
  169         if (error)
  170                 goto bad;
  171         /*
  172          * Make sure that a VM object is created for VMIO support.
  173          */
  174         if (vp->v_type == VREG) {
  175                 if ((error = vfs_object_create(vp, p, cred)) != 0)
  176                         goto bad;
  177         }
  178 
  179         if (fmode & FWRITE)
  180                 vp->v_writecount++;
  181         return (0);
  182 bad:
  183         vput(vp);
  184         return (error);
  185 }
  186 
  187 /*
  188  * Check for write permissions on the specified vnode.
  189  * Prototype text segments cannot be written.
  190  */
  191 int
  192 vn_writechk(vp)
  193         register struct vnode *vp;
  194 {
  195 
  196         /*
  197          * If there's shared text associated with
  198          * the vnode, try to free it up once.  If
  199          * we fail, we can't allow writing.
  200          */
  201         if (vp->v_flag & VTEXT)
  202                 return (ETXTBSY);
  203         return (0);
  204 }
  205 
  206 /*
  207  * Vnode close call
  208  */
  209 int
  210 vn_close(vp, flags, cred, p)
  211         register struct vnode *vp;
  212         int flags;
  213         struct ucred *cred;
  214         struct proc *p;
  215 {
  216         int error;
  217 
  218         if (flags & FWRITE)
  219                 vp->v_writecount--;
  220         error = VOP_CLOSE(vp, flags, cred, p);
  221         vrele(vp);
  222         return (error);
  223 }
  224 
  225 /*
  226  * Package up an I/O request on a vnode into a uio and do it.
  227  */
  228 int
  229 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
  230         enum uio_rw rw;
  231         struct vnode *vp;
  232         caddr_t base;
  233         int len;
  234         off_t offset;
  235         enum uio_seg segflg;
  236         int ioflg;
  237         struct ucred *cred;
  238         int *aresid;
  239         struct proc *p;
  240 {
  241         struct uio auio;
  242         struct iovec aiov;
  243         int error;
  244 
  245         if ((ioflg & IO_NODELOCKED) == 0)
  246                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  247         auio.uio_iov = &aiov;
  248         auio.uio_iovcnt = 1;
  249         aiov.iov_base = base;
  250         aiov.iov_len = len;
  251         auio.uio_resid = len;
  252         auio.uio_offset = offset;
  253         auio.uio_segflg = segflg;
  254         auio.uio_rw = rw;
  255         auio.uio_procp = p;
  256         if (rw == UIO_READ) {
  257                 error = VOP_READ(vp, &auio, ioflg, cred);
  258         } else {
  259                 error = VOP_WRITE(vp, &auio, ioflg, cred);
  260         }
  261         if (aresid)
  262                 *aresid = auio.uio_resid;
  263         else
  264                 if (auio.uio_resid && error == 0)
  265                         error = EIO;
  266         if ((ioflg & IO_NODELOCKED) == 0)
  267                 VOP_UNLOCK(vp, 0, p);
  268         return (error);
  269 }
  270 
  271 /*
  272  * File table vnode read routine.
  273  */
  274 static int
  275 vn_read(fp, uio, cred, flags)
  276         struct file *fp;
  277         struct uio *uio;
  278         struct ucred *cred;
  279         int flags;
  280 {
  281         struct vnode *vp = (struct vnode *)fp->f_data;
  282         struct proc *p = uio->uio_procp;
  283         int error, ioflag;
  284 
  285         ioflag = 0;
  286         if (fp->f_flag & FNONBLOCK)
  287                 ioflag |= IO_NDELAY;
  288         VOP_LEASE(vp, p, cred, LEASE_READ);
  289         vn_lock(vp, LK_SHARED | LK_NOPAUSE | LK_RETRY, p);
  290         if ((flags & FOF_OFFSET) == 0)
  291                 uio->uio_offset = fp->f_offset;
  292 
  293         /*
  294          * Sequential read heuristic.
  295          * If we have been doing sequential input,
  296          * a rewind operation doesn't turn off
  297          * sequential input mode.
  298          */
  299         if ((uio->uio_offset == 0 && fp->f_seqcount > 0) ||
  300             uio->uio_offset == fp->f_nextread) {
  301                 int tmpseq = fp->f_seqcount;
  302                 /*
  303                  * XXX we assume that the filesystem block size is
  304                  * the default.  Not true, but still gives us a pretty
  305                  * good indicator of how sequential the read operations
  306                  * are.
  307                  */
  308                 tmpseq += (uio->uio_resid + BKVASIZE - 1) / BKVASIZE;
  309                 if (tmpseq >= 127)
  310                         tmpseq = 127;
  311                 fp->f_seqcount = tmpseq;
  312                 ioflag |= fp->f_seqcount << 16;
  313         } else {
  314                 if (fp->f_seqcount > 1)
  315                         fp->f_seqcount = 1;
  316                 else
  317                         fp->f_seqcount = 0;
  318         }
  319         error = VOP_READ(vp, uio, ioflag, cred);
  320         if ((flags & FOF_OFFSET) == 0)
  321                 fp->f_offset = uio->uio_offset;
  322         fp->f_nextread = uio->uio_offset;
  323         VOP_UNLOCK(vp, 0, p);
  324         return (error);
  325 }
  326 
  327 /*
  328  * File table vnode write routine.
  329  */
  330 static int
  331 vn_write(fp, uio, cred, flags)
  332         struct file *fp;
  333         struct uio *uio;
  334         struct ucred *cred;
  335         int flags;
  336 {
  337         struct vnode *vp = (struct vnode *)fp->f_data;
  338         struct proc *p = uio->uio_procp;
  339         int error, ioflag;
  340 
  341         ioflag = IO_UNIT;
  342         if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
  343                 ioflag |= IO_APPEND;
  344         if (fp->f_flag & FNONBLOCK)
  345                 ioflag |= IO_NDELAY;
  346         if ((fp->f_flag & O_FSYNC) ||
  347             (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
  348                 ioflag |= IO_SYNC;
  349         VOP_LEASE(vp, p, cred, LEASE_WRITE);
  350         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  351         if ((flags & FOF_OFFSET) == 0)
  352                 uio->uio_offset = fp->f_offset;
  353         error = VOP_WRITE(vp, uio, ioflag, cred);
  354         if ((flags & FOF_OFFSET) == 0)
  355                 fp->f_offset = uio->uio_offset;
  356         VOP_UNLOCK(vp, 0, p);
  357         return (error);
  358 }
  359 
  360 /*
  361  * File table vnode stat routine.
  362  */
  363 int
  364 vn_stat(vp, sb, p)
  365         struct vnode *vp;
  366         register struct stat *sb;
  367         struct proc *p;
  368 {
  369         struct vattr vattr;
  370         register struct vattr *vap;
  371         int error;
  372         u_short mode;
  373 
  374         vap = &vattr;
  375         error = VOP_GETATTR(vp, vap, p->p_ucred, p);
  376         if (error)
  377                 return (error);
  378 
  379         /*
  380          * Zero the spare stat fields
  381          */
  382         sb->st_lspare = 0;
  383         sb->st_qspare[0] = 0;
  384         sb->st_qspare[1] = 0;
  385 
  386         /*
  387          * Copy from vattr table
  388          */
  389         sb->st_dev = vap->va_fsid;
  390         sb->st_ino = vap->va_fileid;
  391         mode = vap->va_mode;
  392         switch (vap->va_type) {
  393         case VREG:
  394                 mode |= S_IFREG;
  395                 break;
  396         case VDIR:
  397                 mode |= S_IFDIR;
  398                 break;
  399         case VBLK:
  400                 mode |= S_IFBLK;
  401                 break;
  402         case VCHR:
  403                 mode |= S_IFCHR;
  404                 break;
  405         case VLNK:
  406                 mode |= S_IFLNK;
  407                 /* This is a cosmetic change, symlinks do not have a mode. */
  408                 if (vp->v_mount->mnt_flag & MNT_NOSYMFOLLOW)
  409                         sb->st_mode &= ~ACCESSPERMS;    /* 0000 */
  410                 else
  411                         sb->st_mode |= ACCESSPERMS;     /* 0777 */
  412                 break;
  413         case VSOCK:
  414                 mode |= S_IFSOCK;
  415                 break;
  416         case VFIFO:
  417                 mode |= S_IFIFO;
  418                 break;
  419         default:
  420                 return (EBADF);
  421         };
  422         sb->st_mode = mode;
  423         sb->st_nlink = vap->va_nlink;
  424         sb->st_uid = vap->va_uid;
  425         sb->st_gid = vap->va_gid;
  426         sb->st_rdev = vap->va_rdev;
  427         sb->st_size = vap->va_size;
  428         sb->st_atimespec = vap->va_atime;
  429         sb->st_mtimespec = vap->va_mtime;
  430         sb->st_ctimespec = vap->va_ctime;
  431         sb->st_blksize = vap->va_blocksize;
  432         sb->st_flags = vap->va_flags;
  433         if (p->p_ucred->cr_uid != 0)
  434                 sb->st_gen = 0;
  435         else
  436                 sb->st_gen = vap->va_gen;
  437 
  438 #if (S_BLKSIZE == 512)
  439         /* Optimize this case */
  440         sb->st_blocks = vap->va_bytes >> 9;
  441 #else
  442         sb->st_blocks = vap->va_bytes / S_BLKSIZE;
  443 #endif
  444         return (0);
  445 }
  446 
  447 /*
  448  * File table vnode ioctl routine.
  449  */
  450 static int
  451 vn_ioctl(fp, com, data, p)
  452         struct file *fp;
  453         u_long com;
  454         caddr_t data;
  455         struct proc *p;
  456 {
  457         register struct vnode *vp = ((struct vnode *)fp->f_data);
  458         struct vattr vattr;
  459         int error;
  460 
  461         switch (vp->v_type) {
  462 
  463         case VREG:
  464         case VDIR:
  465                 if (com == FIONREAD) {
  466                         error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
  467                         if (error)
  468                                 return (error);
  469                         *(int *)data = vattr.va_size - fp->f_offset;
  470                         return (0);
  471                 }
  472                 if (com == FIONBIO || com == FIOASYNC)  /* XXX */
  473                         return (0);                     /* XXX */
  474                 /* fall into ... */
  475 
  476         default:
  477 #if 0
  478                 return (ENOTTY);
  479 #endif
  480         case VFIFO:
  481         case VCHR:
  482         case VBLK:
  483                 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
  484                 if (error == 0 && com == TIOCSCTTY) {
  485 
  486                         /* Do nothing if reassigning same control tty */
  487                         if (p->p_session->s_ttyvp == vp)
  488                                 return (0);
  489 
  490                         /* Get rid of reference to old control tty */
  491                         if (p->p_session->s_ttyvp)
  492                                 vrele(p->p_session->s_ttyvp);
  493 
  494                         p->p_session->s_ttyvp = vp;
  495                         VREF(vp);
  496                 }
  497                 return (error);
  498         }
  499 }
  500 
  501 /*
  502  * File table vnode poll routine.
  503  */
  504 static int
  505 vn_poll(fp, events, cred, p)
  506         struct file *fp;
  507         int events;
  508         struct ucred *cred;
  509         struct proc *p;
  510 {
  511 
  512         return (VOP_POLL(((struct vnode *)fp->f_data), events, cred, p));
  513 }
  514 
  515 /*
  516  * Check that the vnode is still valid, and if so
  517  * acquire requested lock.
  518  */
  519 int
  520 #ifndef DEBUG_LOCKS
  521 vn_lock(vp, flags, p)
  522 #else
  523 debug_vn_lock(vp, flags, p, filename, line)
  524 #endif
  525         struct vnode *vp;
  526         int flags;
  527         struct proc *p;
  528 #ifdef  DEBUG_LOCKS
  529         const char *filename;
  530         int line;
  531 #endif
  532 {
  533         int error;
  534         
  535         do {
  536                 if ((flags & LK_INTERLOCK) == 0)
  537                         simple_lock(&vp->v_interlock);
  538                 if (vp->v_flag & VXLOCK) {
  539                         vp->v_flag |= VXWANT;
  540                         simple_unlock(&vp->v_interlock);
  541                         tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
  542                         error = ENOENT;
  543                 } else {
  544 #ifdef  DEBUG_LOCKS
  545                         vp->filename = filename;
  546                         vp->line = line;
  547 #endif
  548                         error = VOP_LOCK(vp,
  549                                     flags | LK_NOPAUSE | LK_INTERLOCK, p);
  550                         if (error == 0)
  551                                 return (error);
  552                 }
  553                 flags &= ~LK_INTERLOCK;
  554         } while (flags & LK_RETRY);
  555         return (error);
  556 }
  557 
  558 /*
  559  * File table vnode close routine.
  560  */
  561 static int
  562 vn_closefile(fp, p)
  563         struct file *fp;
  564         struct proc *p;
  565 {
  566 
  567         return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
  568                 fp->f_cred, p));
  569 }

Cache object: a3d8b95e73903ec9f0db89b663716c33


[ 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.