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 /*      $NetBSD: vfs_vnops.c,v 1.160.4.1 2009/04/04 23:36:28 snj Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran.
    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  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1982, 1986, 1989, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  * (c) UNIX System Laboratories, Inc.
   36  * All or some portions of this file are derived from material licensed
   37  * to the University of California by American Telephone and Telegraph
   38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   39  * the permission of UNIX System Laboratories, Inc.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  * 3. Neither the name of the University nor the names of its contributors
   50  *    may be used to endorse or promote products derived from this software
   51  *    without specific prior written permission.
   52  *
   53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   63  * SUCH DAMAGE.
   64  *
   65  *      @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
   66  */
   67 
   68 #include <sys/cdefs.h>
   69 __KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.160.4.1 2009/04/04 23:36:28 snj Exp $");
   70 
   71 #include "fs_union.h"
   72 #include "veriexec.h"
   73 
   74 #include <sys/param.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/file.h>
   78 #include <sys/stat.h>
   79 #include <sys/buf.h>
   80 #include <sys/proc.h>
   81 #include <sys/malloc.h>
   82 #include <sys/mount.h>
   83 #include <sys/namei.h>
   84 #include <sys/vnode.h>
   85 #include <sys/ioctl.h>
   86 #include <sys/tty.h>
   87 #include <sys/poll.h>
   88 #include <sys/kauth.h>
   89 #include <sys/syslog.h>
   90 #include <sys/fstrans.h>
   91 #include <sys/atomic.h>
   92 #include <sys/filedesc.h>
   93 #include <sys/wapbl.h>
   94 
   95 #include <miscfs/specfs/specdev.h>
   96 
   97 #include <uvm/uvm_extern.h>
   98 #include <uvm/uvm_readahead.h>
   99 
  100 #ifdef UNION
  101 #include <fs/union/union.h>
  102 #endif
  103 
  104 #if defined(LKM) || defined(UNION)
  105 int (*vn_union_readdir_hook) (struct vnode **, struct file *, struct lwp *);
  106 #endif
  107 
  108 #include <sys/verified_exec.h>
  109 
  110 static int vn_read(file_t *fp, off_t *offset, struct uio *uio,
  111             kauth_cred_t cred, int flags);
  112 static int vn_write(file_t *fp, off_t *offset, struct uio *uio,
  113             kauth_cred_t cred, int flags);
  114 static int vn_closefile(file_t *fp);
  115 static int vn_poll(file_t *fp, int events);
  116 static int vn_fcntl(file_t *fp, u_int com, void *data);
  117 static int vn_statfile(file_t *fp, struct stat *sb);
  118 static int vn_ioctl(file_t *fp, u_long com, void *data);
  119 
  120 const struct fileops vnops = {
  121         .fo_read = vn_read,
  122         .fo_write = vn_write,
  123         .fo_ioctl = vn_ioctl,
  124         .fo_fcntl = vn_fcntl,
  125         .fo_poll = vn_poll,
  126         .fo_stat = vn_statfile,
  127         .fo_close = vn_closefile,
  128         .fo_kqfilter = vn_kqfilter,
  129         .fo_drain = fnullop_drain,
  130 };
  131 
  132 /*
  133  * Common code for vnode open operations.
  134  * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
  135  */
  136 int
  137 vn_open(struct nameidata *ndp, int fmode, int cmode)
  138 {
  139         struct vnode *vp;
  140         struct lwp *l = curlwp;
  141         kauth_cred_t cred = l->l_cred;
  142         struct vattr va;
  143         int error;
  144         char *path;
  145 
  146         ndp->ni_cnd.cn_flags &= TRYEMULROOT;
  147 
  148         if (fmode & O_CREAT) {
  149                 ndp->ni_cnd.cn_nameiop = CREATE;
  150                 ndp->ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF;
  151                 if ((fmode & O_EXCL) == 0 &&
  152                     ((fmode & O_NOFOLLOW) == 0))
  153                         ndp->ni_cnd.cn_flags |= FOLLOW;
  154         } else {
  155                 ndp->ni_cnd.cn_nameiop = LOOKUP;
  156                 ndp->ni_cnd.cn_flags |= LOCKLEAF;
  157                 if ((fmode & O_NOFOLLOW) == 0)
  158                         ndp->ni_cnd.cn_flags |= FOLLOW;
  159         }
  160 
  161         VERIEXEC_PATH_GET(ndp->ni_dirp, ndp->ni_segflg, ndp->ni_dirp, path);
  162 
  163         error = namei(ndp);
  164         if (error)
  165                 goto out;
  166 
  167         vp = ndp->ni_vp;
  168 
  169 #if NVERIEXEC > 0
  170         error = veriexec_openchk(l, ndp->ni_vp, ndp->ni_dirp, fmode);
  171         if (error)
  172                 goto bad;
  173 #endif /* NVERIEXEC > 0 */
  174 
  175         if (fmode & O_CREAT) {
  176                 if (ndp->ni_vp == NULL) {
  177                         VATTR_NULL(&va);
  178                         va.va_type = VREG;
  179                         va.va_mode = cmode;
  180                         if (fmode & O_EXCL)
  181                                  va.va_vaflags |= VA_EXCLUSIVE;
  182                         error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
  183                                            &ndp->ni_cnd, &va);
  184                         if (error)
  185                                 goto out;
  186                         fmode &= ~O_TRUNC;
  187                         vp = ndp->ni_vp;
  188                 } else {
  189                         VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
  190                         if (ndp->ni_dvp == ndp->ni_vp)
  191                                 vrele(ndp->ni_dvp);
  192                         else
  193                                 vput(ndp->ni_dvp);
  194                         ndp->ni_dvp = NULL;
  195                         vp = ndp->ni_vp;
  196                         if (fmode & O_EXCL) {
  197                                 error = EEXIST;
  198                                 goto bad;
  199                         }
  200                         fmode &= ~O_CREAT;
  201                 }
  202         } else {
  203                 vp = ndp->ni_vp;
  204         }
  205         if (vp->v_type == VSOCK) {
  206                 error = EOPNOTSUPP;
  207                 goto bad;
  208         }
  209         if (ndp->ni_vp->v_type == VLNK) {
  210                 error = EFTYPE;
  211                 goto bad;
  212         }
  213 
  214         if ((fmode & O_CREAT) == 0) {
  215                 error = vn_openchk(vp, cred, fmode);
  216                 if (error != 0)
  217                         goto bad;
  218         }
  219 
  220         if (fmode & O_TRUNC) {
  221                 VOP_UNLOCK(vp, 0);                      /* XXX */
  222 
  223                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */
  224                 VATTR_NULL(&va);
  225                 va.va_size = 0;
  226                 error = VOP_SETATTR(vp, &va, cred);
  227                 if (error != 0)
  228                         goto bad;
  229         }
  230         if ((error = VOP_OPEN(vp, fmode, cred)) != 0)
  231                 goto bad;
  232         if (fmode & FWRITE) {
  233                 mutex_enter(&vp->v_interlock);
  234                 vp->v_writecount++;
  235                 mutex_exit(&vp->v_interlock);
  236         }
  237 
  238 bad:
  239         if (error)
  240                 vput(vp);
  241 out:
  242         VERIEXEC_PATH_PUT(path);
  243         return (error);
  244 }
  245 
  246 /*
  247  * Check for write permissions on the specified vnode.
  248  * Prototype text segments cannot be written.
  249  */
  250 int
  251 vn_writechk(struct vnode *vp)
  252 {
  253 
  254         /*
  255          * If the vnode is in use as a process's text,
  256          * we can't allow writing.
  257          */
  258         if (vp->v_iflag & VI_TEXT)
  259                 return (ETXTBSY);
  260         return (0);
  261 }
  262 
  263 int
  264 vn_openchk(struct vnode *vp, kauth_cred_t cred, int fflags)
  265 {
  266         int permbits = 0;
  267         int error;
  268 
  269         if ((fflags & FREAD) != 0) {
  270                 permbits = VREAD;
  271         }
  272         if ((fflags & (FWRITE | O_TRUNC)) != 0) {
  273                 permbits |= VWRITE;
  274                 if (vp->v_type == VDIR) {
  275                         error = EISDIR;
  276                         goto bad;
  277                 }
  278                 error = vn_writechk(vp);
  279                 if (error != 0)
  280                         goto bad;
  281         }
  282         error = VOP_ACCESS(vp, permbits, cred);
  283 bad:
  284         return error;
  285 }
  286 
  287 /*
  288  * Mark a vnode as having executable mappings.
  289  */
  290 void
  291 vn_markexec(struct vnode *vp)
  292 {
  293 
  294         if ((vp->v_iflag & VI_EXECMAP) != 0) {
  295                 /* Safe unlocked, as long as caller holds a reference. */
  296                 return;
  297         }
  298 
  299         mutex_enter(&vp->v_interlock);
  300         if ((vp->v_iflag & VI_EXECMAP) == 0) {
  301                 atomic_add_int(&uvmexp.filepages, -vp->v_uobj.uo_npages);
  302                 atomic_add_int(&uvmexp.execpages, vp->v_uobj.uo_npages);
  303                 vp->v_iflag |= VI_EXECMAP;
  304         }
  305         mutex_exit(&vp->v_interlock);
  306 }
  307 
  308 /*
  309  * Mark a vnode as being the text of a process.
  310  * Fail if the vnode is currently writable.
  311  */
  312 int
  313 vn_marktext(struct vnode *vp)
  314 {
  315 
  316         if ((vp->v_iflag & (VI_TEXT|VI_EXECMAP)) == (VI_TEXT|VI_EXECMAP)) {
  317                 /* Safe unlocked, as long as caller holds a reference. */
  318                 return (0);
  319         }
  320 
  321         mutex_enter(&vp->v_interlock);
  322         if (vp->v_writecount != 0) {
  323                 KASSERT((vp->v_iflag & VI_TEXT) == 0);
  324                 mutex_exit(&vp->v_interlock);
  325                 return (ETXTBSY);
  326         }
  327         if ((vp->v_iflag & VI_EXECMAP) == 0) {
  328                 atomic_add_int(&uvmexp.filepages, -vp->v_uobj.uo_npages);
  329                 atomic_add_int(&uvmexp.execpages, vp->v_uobj.uo_npages);
  330         }
  331         vp->v_iflag |= (VI_TEXT | VI_EXECMAP);
  332         mutex_exit(&vp->v_interlock);
  333         return (0);
  334 }
  335 
  336 /*
  337  * Vnode close call
  338  *
  339  * Note: takes an unlocked vnode, while VOP_CLOSE takes a locked node.
  340  */
  341 int
  342 vn_close(struct vnode *vp, int flags, kauth_cred_t cred)
  343 {
  344         int error;
  345 
  346         if (flags & FWRITE) {
  347                 mutex_enter(&vp->v_interlock);
  348                 vp->v_writecount--;
  349                 mutex_exit(&vp->v_interlock);
  350         }
  351         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  352         error = VOP_CLOSE(vp, flags, cred);
  353         vput(vp);
  354         return (error);
  355 }
  356 
  357 /*
  358  * Package up an I/O request on a vnode into a uio and do it.
  359  */
  360 int
  361 vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset,
  362     enum uio_seg segflg, int ioflg, kauth_cred_t cred, size_t *aresid,
  363     struct lwp *l)
  364 {
  365         struct uio auio;
  366         struct iovec aiov;
  367         int error;
  368 
  369         if ((ioflg & IO_NODELOCKED) == 0) {
  370                 if (rw == UIO_READ) {
  371                         vn_lock(vp, LK_SHARED | LK_RETRY);
  372                 } else /* UIO_WRITE */ {
  373                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  374                 }
  375         }
  376         auio.uio_iov = &aiov;
  377         auio.uio_iovcnt = 1;
  378         aiov.iov_base = base;
  379         aiov.iov_len = len;
  380         auio.uio_resid = len;
  381         auio.uio_offset = offset;
  382         auio.uio_rw = rw;
  383         if (segflg == UIO_SYSSPACE) {
  384                 UIO_SETUP_SYSSPACE(&auio);
  385         } else {
  386                 auio.uio_vmspace = l->l_proc->p_vmspace;
  387         }
  388         if (rw == UIO_READ) {
  389                 error = VOP_READ(vp, &auio, ioflg, cred);
  390         } else {
  391                 error = VOP_WRITE(vp, &auio, ioflg, cred);
  392         }
  393         if (aresid)
  394                 *aresid = auio.uio_resid;
  395         else
  396                 if (auio.uio_resid && error == 0)
  397                         error = EIO;
  398         if ((ioflg & IO_NODELOCKED) == 0) {
  399                 VOP_UNLOCK(vp, 0);
  400         }
  401         return (error);
  402 }
  403 
  404 int
  405 vn_readdir(file_t *fp, char *bf, int segflg, u_int count, int *done,
  406     struct lwp *l, off_t **cookies, int *ncookies)
  407 {
  408         struct vnode *vp = (struct vnode *)fp->f_data;
  409         struct iovec aiov;
  410         struct uio auio;
  411         int error, eofflag;
  412 
  413         /* Limit the size on any kernel buffers used by VOP_READDIR */
  414         count = min(MAXBSIZE, count);
  415 
  416 unionread:
  417         if (vp->v_type != VDIR)
  418                 return (EINVAL);
  419         aiov.iov_base = bf;
  420         aiov.iov_len = count;
  421         auio.uio_iov = &aiov;
  422         auio.uio_iovcnt = 1;
  423         auio.uio_rw = UIO_READ;
  424         if (segflg == UIO_SYSSPACE) {
  425                 UIO_SETUP_SYSSPACE(&auio);
  426         } else {
  427                 KASSERT(l == curlwp);
  428                 auio.uio_vmspace = l->l_proc->p_vmspace;
  429         }
  430         auio.uio_resid = count;
  431         vn_lock(vp, LK_SHARED | LK_RETRY);
  432         auio.uio_offset = fp->f_offset;
  433         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, cookies,
  434                     ncookies);
  435         FILE_LOCK(fp);
  436         fp->f_offset = auio.uio_offset;
  437         FILE_UNLOCK(fp);
  438         VOP_UNLOCK(vp, 0);
  439         if (error)
  440                 return (error);
  441 
  442 #if defined(UNION) || defined(LKM)
  443         if (count == auio.uio_resid && vn_union_readdir_hook) {
  444                 struct vnode *ovp = vp;
  445 
  446                 error = (*vn_union_readdir_hook)(&vp, fp, l);
  447                 if (error)
  448                         return (error);
  449                 if (vp != ovp)
  450                         goto unionread;
  451         }
  452 #endif /* UNION || LKM */
  453 
  454         if (count == auio.uio_resid && (vp->v_vflag & VV_ROOT) &&
  455             (vp->v_mount->mnt_flag & MNT_UNION)) {
  456                 struct vnode *tvp = vp;
  457                 vp = vp->v_mount->mnt_vnodecovered;
  458                 VREF(vp);
  459                 FILE_LOCK(fp);
  460                 fp->f_data = vp;
  461                 fp->f_offset = 0;
  462                 FILE_UNLOCK(fp);
  463                 vrele(tvp);
  464                 goto unionread;
  465         }
  466         *done = count - auio.uio_resid;
  467         return error;
  468 }
  469 
  470 /*
  471  * File table vnode read routine.
  472  */
  473 static int
  474 vn_read(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred,
  475     int flags)
  476 {
  477         struct vnode *vp = (struct vnode *)fp->f_data;
  478         int count, error, ioflag, fflag;
  479 
  480         ioflag = IO_ADV_ENCODE(fp->f_advice);
  481         fflag = fp->f_flag;
  482         if (fflag & FNONBLOCK)
  483                 ioflag |= IO_NDELAY;
  484         if ((fflag & (FFSYNC | FRSYNC)) == (FFSYNC | FRSYNC))
  485                 ioflag |= IO_SYNC;
  486         if (fflag & FALTIO)
  487                 ioflag |= IO_ALTSEMANTICS;
  488         if (fflag & FDIRECT)
  489                 ioflag |= IO_DIRECT;
  490         vn_lock(vp, LK_SHARED | LK_RETRY);
  491         uio->uio_offset = *offset;
  492         count = uio->uio_resid;
  493         error = VOP_READ(vp, uio, ioflag, cred);
  494         if (flags & FOF_UPDATE_OFFSET)
  495                 *offset += count - uio->uio_resid;
  496         VOP_UNLOCK(vp, 0);
  497         return (error);
  498 }
  499 
  500 /*
  501  * File table vnode write routine.
  502  */
  503 static int
  504 vn_write(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred,
  505     int flags)
  506 {
  507         struct vnode *vp = (struct vnode *)fp->f_data;
  508         int count, error, ioflag, fflag;
  509 
  510         ioflag = IO_ADV_ENCODE(fp->f_advice) | IO_UNIT;
  511         fflag = fp->f_flag;
  512         if (vp->v_type == VREG && (fflag & O_APPEND))
  513                 ioflag |= IO_APPEND;
  514         if (fflag & FNONBLOCK)
  515                 ioflag |= IO_NDELAY;
  516         if (fflag & FFSYNC ||
  517             (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
  518                 ioflag |= IO_SYNC;
  519         else if (fflag & FDSYNC)
  520                 ioflag |= IO_DSYNC;
  521         if (fflag & FALTIO)
  522                 ioflag |= IO_ALTSEMANTICS;
  523         if (fflag & FDIRECT)
  524                 ioflag |= IO_DIRECT;
  525         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  526         uio->uio_offset = *offset;
  527         count = uio->uio_resid;
  528         error = VOP_WRITE(vp, uio, ioflag, cred);
  529         if (flags & FOF_UPDATE_OFFSET) {
  530                 if (ioflag & IO_APPEND) {
  531                         /*
  532                          * SUSv3 describes behaviour for count = 0 as following:
  533                          * "Before any action ... is taken, and if nbyte is zero
  534                          * and the file is a regular file, the write() function
  535                          * ... in the absence of errors ... shall return zero
  536                          * and have no other results."
  537                          */ 
  538                         if (count)
  539                                 *offset = uio->uio_offset;
  540                 } else
  541                         *offset += count - uio->uio_resid;
  542         }
  543         VOP_UNLOCK(vp, 0);
  544         return (error);
  545 }
  546 
  547 /*
  548  * File table vnode stat routine.
  549  */
  550 static int
  551 vn_statfile(file_t *fp, struct stat *sb)
  552 {
  553         struct vnode *vp = (struct vnode *)fp->f_data;
  554 
  555         return vn_stat(vp, sb);
  556 }
  557 
  558 int
  559 vn_stat(struct vnode *vp, struct stat *sb)
  560 {
  561         struct vattr va;
  562         int error;
  563         mode_t mode;
  564 
  565         error = VOP_GETATTR(vp, &va, kauth_cred_get());
  566         if (error)
  567                 return (error);
  568         /*
  569          * Copy from vattr table
  570          */
  571         sb->st_dev = va.va_fsid;
  572         sb->st_ino = va.va_fileid;
  573         mode = va.va_mode;
  574         switch (vp->v_type) {
  575         case VREG:
  576                 mode |= S_IFREG;
  577                 break;
  578         case VDIR:
  579                 mode |= S_IFDIR;
  580                 break;
  581         case VBLK:
  582                 mode |= S_IFBLK;
  583                 break;
  584         case VCHR:
  585                 mode |= S_IFCHR;
  586                 break;
  587         case VLNK:
  588                 mode |= S_IFLNK;
  589                 break;
  590         case VSOCK:
  591                 mode |= S_IFSOCK;
  592                 break;
  593         case VFIFO:
  594                 mode |= S_IFIFO;
  595                 break;
  596         default:
  597                 return (EBADF);
  598         };
  599         sb->st_mode = mode;
  600         sb->st_nlink = va.va_nlink;
  601         sb->st_uid = va.va_uid;
  602         sb->st_gid = va.va_gid;
  603         sb->st_rdev = va.va_rdev;
  604         sb->st_size = va.va_size;
  605         sb->st_atimespec = va.va_atime;
  606         sb->st_mtimespec = va.va_mtime;
  607         sb->st_ctimespec = va.va_ctime;
  608         sb->st_birthtimespec = va.va_birthtime;
  609         sb->st_blksize = va.va_blocksize;
  610         sb->st_flags = va.va_flags;
  611         sb->st_gen = 0;
  612         sb->st_blocks = va.va_bytes / S_BLKSIZE;
  613         return (0);
  614 }
  615 
  616 /*
  617  * File table vnode fcntl routine.
  618  */
  619 static int
  620 vn_fcntl(file_t *fp, u_int com, void *data)
  621 {
  622         struct vnode *vp = fp->f_data;
  623         int error;
  624 
  625         error = VOP_FCNTL(vp, com, data, fp->f_flag, kauth_cred_get());
  626         return (error);
  627 }
  628 
  629 /*
  630  * File table vnode ioctl routine.
  631  */
  632 static int
  633 vn_ioctl(file_t *fp, u_long com, void *data)
  634 {
  635         struct vnode *vp = fp->f_data, *ovp;
  636         struct vattr vattr;
  637         int error;
  638 
  639         switch (vp->v_type) {
  640 
  641         case VREG:
  642         case VDIR:
  643                 if (com == FIONREAD) {
  644                         error = VOP_GETATTR(vp, &vattr,
  645                             kauth_cred_get());
  646                         if (error)
  647                                 return (error);
  648                         *(int *)data = vattr.va_size - fp->f_offset;
  649                         return (0);
  650                 }
  651                 if ((com == FIONWRITE) || (com == FIONSPACE)) {
  652                         /*
  653                          * Files don't have send queues, so there never
  654                          * are any bytes in them, nor is there any
  655                          * open space in them.
  656                          */
  657                         *(int *)data = 0;
  658                         return (0);
  659                 }
  660                 if (com == FIOGETBMAP) {
  661                         daddr_t *block;
  662 
  663                         if (*(daddr_t *)data < 0)
  664                                 return (EINVAL);
  665                         block = (daddr_t *)data;
  666                         return (VOP_BMAP(vp, *block, NULL, block, NULL));
  667                 }
  668                 if (com == OFIOGETBMAP) {
  669                         daddr_t ibn, obn;
  670 
  671                         if (*(int32_t *)data < 0)
  672                                 return (EINVAL);
  673                         ibn = (daddr_t)*(int32_t *)data;
  674                         error = VOP_BMAP(vp, ibn, NULL, &obn, NULL);
  675                         *(int32_t *)data = (int32_t)obn;
  676                         return error;
  677                 }
  678                 if (com == FIONBIO || com == FIOASYNC)  /* XXX */
  679                         return (0);                     /* XXX */
  680                 /* fall into ... */
  681         case VFIFO:
  682         case VCHR:
  683         case VBLK:
  684                 error = VOP_IOCTL(vp, com, data, fp->f_flag,
  685                     kauth_cred_get());
  686                 if (error == 0 && com == TIOCSCTTY) {
  687                         VREF(vp);
  688                         mutex_enter(proc_lock);
  689                         ovp = curproc->p_session->s_ttyvp;
  690                         curproc->p_session->s_ttyvp = vp;
  691                         mutex_exit(proc_lock);
  692                         if (ovp != NULL)
  693                                 vrele(ovp);
  694                 }
  695                 return (error);
  696 
  697         default:
  698                 return (EPASSTHROUGH);
  699         }
  700 }
  701 
  702 /*
  703  * File table vnode poll routine.
  704  */
  705 static int
  706 vn_poll(file_t *fp, int events)
  707 {
  708 
  709         return (VOP_POLL(fp->f_data, events));
  710 }
  711 
  712 /*
  713  * File table vnode kqfilter routine.
  714  */
  715 int
  716 vn_kqfilter(file_t *fp, struct knote *kn)
  717 {
  718 
  719         return (VOP_KQFILTER(fp->f_data, kn));
  720 }
  721 
  722 /*
  723  * Check that the vnode is still valid, and if so
  724  * acquire requested lock.
  725  */
  726 int
  727 vn_lock(struct vnode *vp, int flags)
  728 {
  729         int error;
  730 
  731 #if 0
  732         KASSERT(vp->v_usecount > 0 || (flags & LK_INTERLOCK) != 0
  733             || (vp->v_iflag & VI_ONWORKLST) != 0);
  734 #endif
  735         KASSERT((flags &
  736             ~(LK_INTERLOCK|LK_SHARED|LK_EXCLUSIVE|LK_NOWAIT|LK_RETRY|
  737             LK_CANRECURSE))
  738             == 0);
  739 
  740 #ifdef DIAGNOSTIC
  741         if (wapbl_vphaswapbl(vp))
  742                 WAPBL_JUNLOCK_ASSERT(wapbl_vptomp(vp));
  743 #endif
  744 
  745         do {
  746                 /*
  747                  * XXX PR 37706 forced unmount of file systems is unsafe.
  748                  * Race between vclean() and this the remaining problem.
  749                  */
  750                 if (vp->v_iflag & VI_XLOCK) {
  751                         if ((flags & LK_INTERLOCK) == 0) {
  752                                 mutex_enter(&vp->v_interlock);
  753                         }
  754                         flags &= ~LK_INTERLOCK;
  755                         if (flags & LK_NOWAIT) {
  756                                 mutex_exit(&vp->v_interlock);
  757                                 return EBUSY;
  758                         }
  759                         vwait(vp, VI_XLOCK);
  760                         mutex_exit(&vp->v_interlock);
  761                         error = ENOENT;
  762                 } else {
  763                         if ((flags & LK_INTERLOCK) != 0) {
  764                                 mutex_exit(&vp->v_interlock);
  765                         }
  766                         flags &= ~LK_INTERLOCK;
  767                         error = VOP_LOCK(vp, (flags & ~LK_RETRY));
  768                         if (error == 0 || error == EDEADLK || error == EBUSY)
  769                                 return (error);
  770                 }
  771         } while (flags & LK_RETRY);
  772         return (error);
  773 }
  774 
  775 /*
  776  * File table vnode close routine.
  777  */
  778 static int
  779 vn_closefile(file_t *fp)
  780 {
  781 
  782         return vn_close(fp->f_data, fp->f_flag, fp->f_cred);
  783 }
  784 
  785 /*
  786  * Enable LK_CANRECURSE on lock. Return prior status.
  787  */
  788 u_int
  789 vn_setrecurse(struct vnode *vp)
  790 {
  791         struct vnlock *lkp;
  792 
  793         lkp = (vp->v_vnlock != NULL ? vp->v_vnlock : &vp->v_lock);
  794         atomic_inc_uint(&lkp->vl_canrecurse);
  795 
  796         return 0;
  797 }
  798 
  799 /*
  800  * Called when done with locksetrecurse.
  801  */
  802 void
  803 vn_restorerecurse(struct vnode *vp, u_int flags)
  804 {
  805         struct vnlock *lkp;
  806 
  807         lkp = (vp->v_vnlock != NULL ? vp->v_vnlock : &vp->v_lock);
  808         atomic_dec_uint(&lkp->vl_canrecurse);
  809 }
  810 
  811 /*
  812  * Simplified in-kernel wrapper calls for extended attribute access.
  813  * Both calls pass in a NULL credential, authorizing a "kernel" access.
  814  * Set IO_NODELOCKED in ioflg if the vnode is already locked.
  815  */
  816 int
  817 vn_extattr_get(struct vnode *vp, int ioflg, int attrnamespace,
  818     const char *attrname, size_t *buflen, void *bf, struct lwp *l)
  819 {
  820         struct uio auio;
  821         struct iovec aiov;
  822         int error;
  823 
  824         aiov.iov_len = *buflen;
  825         aiov.iov_base = bf;
  826 
  827         auio.uio_iov = &aiov;
  828         auio.uio_iovcnt = 1;
  829         auio.uio_rw = UIO_READ;
  830         auio.uio_offset = 0;
  831         auio.uio_resid = *buflen;
  832         UIO_SETUP_SYSSPACE(&auio);
  833 
  834         if ((ioflg & IO_NODELOCKED) == 0)
  835                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  836 
  837         error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, NULL, NULL);
  838 
  839         if ((ioflg & IO_NODELOCKED) == 0)
  840                 VOP_UNLOCK(vp, 0);
  841 
  842         if (error == 0)
  843                 *buflen = *buflen - auio.uio_resid;
  844 
  845         return (error);
  846 }
  847 
  848 /*
  849  * XXX Failure mode if partially written?
  850  */
  851 int
  852 vn_extattr_set(struct vnode *vp, int ioflg, int attrnamespace,
  853     const char *attrname, size_t buflen, const void *bf, struct lwp *l)
  854 {
  855         struct uio auio;
  856         struct iovec aiov;
  857         int error;
  858 
  859         aiov.iov_len = buflen;
  860         aiov.iov_base = __UNCONST(bf);          /* XXXUNCONST kills const */
  861 
  862         auio.uio_iov = &aiov;
  863         auio.uio_iovcnt = 1;
  864         auio.uio_rw = UIO_WRITE;
  865         auio.uio_offset = 0;
  866         auio.uio_resid = buflen;
  867         UIO_SETUP_SYSSPACE(&auio);
  868 
  869         if ((ioflg & IO_NODELOCKED) == 0) {
  870                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  871         }
  872 
  873         error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, NULL);
  874 
  875         if ((ioflg & IO_NODELOCKED) == 0) {
  876                 VOP_UNLOCK(vp, 0);
  877         }
  878 
  879         return (error);
  880 }
  881 
  882 int
  883 vn_extattr_rm(struct vnode *vp, int ioflg, int attrnamespace,
  884     const char *attrname, struct lwp *l)
  885 {
  886         int error;
  887 
  888         if ((ioflg & IO_NODELOCKED) == 0) {
  889                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  890         }
  891 
  892         error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, NULL);
  893         if (error == EOPNOTSUPP)
  894                 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, NULL);
  895 
  896         if ((ioflg & IO_NODELOCKED) == 0) {
  897                 VOP_UNLOCK(vp, 0);
  898         }
  899 
  900         return (error);
  901 }
  902 
  903 void
  904 vn_ra_allocctx(struct vnode *vp)
  905 {
  906         struct uvm_ractx *ra = NULL;
  907 
  908         KASSERT(mutex_owned(&vp->v_interlock));
  909 
  910         if (vp->v_type != VREG) {
  911                 return;
  912         }
  913         if (vp->v_ractx != NULL) {
  914                 return;
  915         }
  916         if (vp->v_ractx == NULL) {
  917                 mutex_exit(&vp->v_interlock);
  918                 ra = uvm_ra_allocctx();
  919                 mutex_enter(&vp->v_interlock);
  920                 if (ra != NULL && vp->v_ractx == NULL) {
  921                         vp->v_ractx = ra;
  922                         ra = NULL;
  923                 }
  924         }
  925         if (ra != NULL) {
  926                 uvm_ra_freectx(ra);
  927         }
  928 }

Cache object: cc585fc8232f664d9a79e80152cbbbb6


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