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

Cache object: aeaac45781b2a156e7c4f406bc986ee5


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