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


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

FreeBSD/Linux Kernel Cross Reference
sys/fs/tmpfs/tmpfs_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: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
    9  * 2005 program.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * tmpfs vnode interface.
   35  */
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/fcntl.h>
   41 #include <sys/lockf.h>
   42 #include <sys/namei.h>
   43 #include <sys/priv.h>
   44 #include <sys/proc.h>
   45 #include <sys/sched.h>
   46 #include <sys/sf_buf.h>
   47 #include <sys/stat.h>
   48 #include <sys/systm.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/unistd.h>
   51 #include <sys/vnode.h>
   52 
   53 #include <vm/vm.h>
   54 #include <vm/vm_param.h>
   55 #include <vm/vm_object.h>
   56 #include <vm/vm_page.h>
   57 #include <vm/vm_pager.h>
   58 
   59 #include <machine/_inttypes.h>
   60 
   61 #include <fs/fifofs/fifo.h>
   62 #include <fs/tmpfs/tmpfs_vnops.h>
   63 #include <fs/tmpfs/tmpfs.h>
   64 
   65 SYSCTL_DECL(_vfs_tmpfs);
   66 
   67 static volatile int tmpfs_rename_restarts;
   68 SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
   69     __DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
   70     "Times rename had to restart due to lock contention");
   71 
   72 /* --------------------------------------------------------------------- */
   73 
   74 static int
   75 tmpfs_lookup(struct vop_cachedlookup_args *v)
   76 {
   77         struct vnode *dvp = v->a_dvp;
   78         struct vnode **vpp = v->a_vpp;
   79         struct componentname *cnp = v->a_cnp;
   80 
   81         int error;
   82         struct tmpfs_dirent *de;
   83         struct tmpfs_node *dnode;
   84 
   85         dnode = VP_TO_TMPFS_DIR(dvp);
   86         *vpp = NULLVP;
   87 
   88         /* Check accessibility of requested node as a first step. */
   89         error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread);
   90         if (error != 0)
   91                 goto out;
   92 
   93         /* We cannot be requesting the parent directory of the root node. */
   94         MPASS(IMPLIES(dnode->tn_type == VDIR &&
   95             dnode->tn_dir.tn_parent == dnode,
   96             !(cnp->cn_flags & ISDOTDOT)));
   97 
   98         TMPFS_ASSERT_LOCKED(dnode);
   99         if (dnode->tn_dir.tn_parent == NULL) {
  100                 error = ENOENT;
  101                 goto out;
  102         }
  103         if (cnp->cn_flags & ISDOTDOT) {
  104                 int ltype = 0;
  105 
  106                 ltype = VOP_ISLOCKED(dvp);
  107                 vhold(dvp);
  108                 VOP_UNLOCK(dvp, 0);
  109                 /* Allocate a new vnode on the matching entry. */
  110                 error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
  111                     cnp->cn_lkflags, vpp);
  112 
  113                 vn_lock(dvp, ltype | LK_RETRY);
  114                 vdrop(dvp);
  115         } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
  116                 VREF(dvp);
  117                 *vpp = dvp;
  118                 error = 0;
  119         } else {
  120                 de = tmpfs_dir_lookup(dnode, NULL, cnp);
  121                 if (de != NULL && de->td_node == NULL)
  122                         cnp->cn_flags |= ISWHITEOUT;
  123                 if (de == NULL || de->td_node == NULL) {
  124                         /* The entry was not found in the directory.
  125                          * This is OK if we are creating or renaming an
  126                          * entry and are working on the last component of
  127                          * the path name. */
  128                         if ((cnp->cn_flags & ISLASTCN) &&
  129                             (cnp->cn_nameiop == CREATE || \
  130                             cnp->cn_nameiop == RENAME ||
  131                             (cnp->cn_nameiop == DELETE &&
  132                             cnp->cn_flags & DOWHITEOUT &&
  133                             cnp->cn_flags & ISWHITEOUT))) {
  134                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
  135                                     cnp->cn_thread);
  136                                 if (error != 0)
  137                                         goto out;
  138 
  139                                 /* Keep the component name in the buffer for
  140                                  * future uses. */
  141                                 cnp->cn_flags |= SAVENAME;
  142 
  143                                 error = EJUSTRETURN;
  144                         } else
  145                                 error = ENOENT;
  146                 } else {
  147                         struct tmpfs_node *tnode;
  148 
  149                         /* The entry was found, so get its associated
  150                          * tmpfs_node. */
  151                         tnode = de->td_node;
  152 
  153                         /* If we are not at the last path component and
  154                          * found a non-directory or non-link entry (which
  155                          * may itself be pointing to a directory), raise
  156                          * an error. */
  157                         if ((tnode->tn_type != VDIR &&
  158                             tnode->tn_type != VLNK) &&
  159                             !(cnp->cn_flags & ISLASTCN)) {
  160                                 error = ENOTDIR;
  161                                 goto out;
  162                         }
  163 
  164                         /* If we are deleting or renaming the entry, keep
  165                          * track of its tmpfs_dirent so that it can be
  166                          * easily deleted later. */
  167                         if ((cnp->cn_flags & ISLASTCN) &&
  168                             (cnp->cn_nameiop == DELETE ||
  169                             cnp->cn_nameiop == RENAME)) {
  170                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
  171                                     cnp->cn_thread);
  172                                 if (error != 0)
  173                                         goto out;
  174 
  175                                 /* Allocate a new vnode on the matching entry. */
  176                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
  177                                                 cnp->cn_lkflags, vpp);
  178                                 if (error != 0)
  179                                         goto out;
  180 
  181                                 if ((dnode->tn_mode & S_ISTXT) &&
  182                                   VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) &&
  183                                   VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) {
  184                                         error = EPERM;
  185                                         vput(*vpp);
  186                                         *vpp = NULL;
  187                                         goto out;
  188                                 }
  189                                 cnp->cn_flags |= SAVENAME;
  190                         } else {
  191                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
  192                                                 cnp->cn_lkflags, vpp);
  193                         }
  194                 }
  195         }
  196 
  197         /* Store the result of this lookup in the cache.  Avoid this if the
  198          * request was for creation, as it does not improve timings on
  199          * emprical tests. */
  200         if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
  201                 cache_enter(dvp, *vpp, cnp);
  202 
  203 out:
  204         /* If there were no errors, *vpp cannot be null and it must be
  205          * locked. */
  206         MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp)));
  207 
  208         return error;
  209 }
  210 
  211 /* --------------------------------------------------------------------- */
  212 
  213 static int
  214 tmpfs_create(struct vop_create_args *v)
  215 {
  216         struct vnode *dvp = v->a_dvp;
  217         struct vnode **vpp = v->a_vpp;
  218         struct componentname *cnp = v->a_cnp;
  219         struct vattr *vap = v->a_vap;
  220 
  221         MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
  222 
  223         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
  224 }
  225 /* --------------------------------------------------------------------- */
  226 
  227 static int
  228 tmpfs_mknod(struct vop_mknod_args *v)
  229 {
  230         struct vnode *dvp = v->a_dvp;
  231         struct vnode **vpp = v->a_vpp;
  232         struct componentname *cnp = v->a_cnp;
  233         struct vattr *vap = v->a_vap;
  234 
  235         if (vap->va_type != VBLK && vap->va_type != VCHR &&
  236             vap->va_type != VFIFO)
  237                 return EINVAL;
  238 
  239         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
  240 }
  241 
  242 /* --------------------------------------------------------------------- */
  243 
  244 static int
  245 tmpfs_open(struct vop_open_args *v)
  246 {
  247         struct vnode *vp = v->a_vp;
  248         int mode = v->a_mode;
  249 
  250         int error;
  251         struct tmpfs_node *node;
  252 
  253         MPASS(VOP_ISLOCKED(vp));
  254 
  255         node = VP_TO_TMPFS_NODE(vp);
  256 
  257         /* The file is still active but all its names have been removed
  258          * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
  259          * it is about to die. */
  260         if (node->tn_links < 1)
  261                 return (ENOENT);
  262 
  263         /* If the file is marked append-only, deny write requests. */
  264         if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
  265                 error = EPERM;
  266         else {
  267                 error = 0;
  268                 vnode_create_vobject(vp, node->tn_size, v->a_td);
  269         }
  270 
  271         MPASS(VOP_ISLOCKED(vp));
  272         return error;
  273 }
  274 
  275 /* --------------------------------------------------------------------- */
  276 
  277 static int
  278 tmpfs_close(struct vop_close_args *v)
  279 {
  280         struct vnode *vp = v->a_vp;
  281 
  282         MPASS(VOP_ISLOCKED(vp));
  283 
  284         /* Update node times. */
  285         tmpfs_update(vp);
  286 
  287         return (0);
  288 }
  289 
  290 /* --------------------------------------------------------------------- */
  291 
  292 int
  293 tmpfs_access(struct vop_access_args *v)
  294 {
  295         struct vnode *vp = v->a_vp;
  296         accmode_t accmode = v->a_accmode;
  297         struct ucred *cred = v->a_cred;
  298 
  299         int error;
  300         struct tmpfs_node *node;
  301 
  302         MPASS(VOP_ISLOCKED(vp));
  303 
  304         node = VP_TO_TMPFS_NODE(vp);
  305 
  306         switch (vp->v_type) {
  307         case VDIR:
  308                 /* FALLTHROUGH */
  309         case VLNK:
  310                 /* FALLTHROUGH */
  311         case VREG:
  312                 if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
  313                         error = EROFS;
  314                         goto out;
  315                 }
  316                 break;
  317 
  318         case VBLK:
  319                 /* FALLTHROUGH */
  320         case VCHR:
  321                 /* FALLTHROUGH */
  322         case VSOCK:
  323                 /* FALLTHROUGH */
  324         case VFIFO:
  325                 break;
  326 
  327         default:
  328                 error = EINVAL;
  329                 goto out;
  330         }
  331 
  332         if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
  333                 error = EPERM;
  334                 goto out;
  335         }
  336 
  337         error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
  338             node->tn_gid, accmode, cred, NULL);
  339 
  340 out:
  341         MPASS(VOP_ISLOCKED(vp));
  342 
  343         return error;
  344 }
  345 
  346 /* --------------------------------------------------------------------- */
  347 
  348 int
  349 tmpfs_getattr(struct vop_getattr_args *v)
  350 {
  351         struct vnode *vp = v->a_vp;
  352         struct vattr *vap = v->a_vap;
  353 
  354         struct tmpfs_node *node;
  355 
  356         node = VP_TO_TMPFS_NODE(vp);
  357 
  358         tmpfs_update(vp);
  359 
  360         vap->va_type = vp->v_type;
  361         vap->va_mode = node->tn_mode;
  362         vap->va_nlink = node->tn_links;
  363         vap->va_uid = node->tn_uid;
  364         vap->va_gid = node->tn_gid;
  365         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  366         vap->va_fileid = node->tn_id;
  367         vap->va_size = node->tn_size;
  368         vap->va_blocksize = PAGE_SIZE;
  369         vap->va_atime = node->tn_atime;
  370         vap->va_mtime = node->tn_mtime;
  371         vap->va_ctime = node->tn_ctime;
  372         vap->va_birthtime = node->tn_birthtime;
  373         vap->va_gen = node->tn_gen;
  374         vap->va_flags = node->tn_flags;
  375         vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
  376                 node->tn_rdev : NODEV;
  377         vap->va_bytes = round_page(node->tn_size);
  378         vap->va_filerev = 0;
  379 
  380         return 0;
  381 }
  382 
  383 /* --------------------------------------------------------------------- */
  384 
  385 /* XXX Should this operation be atomic?  I think it should, but code in
  386  * XXX other places (e.g., ufs) doesn't seem to be... */
  387 int
  388 tmpfs_setattr(struct vop_setattr_args *v)
  389 {
  390         struct vnode *vp = v->a_vp;
  391         struct vattr *vap = v->a_vap;
  392         struct ucred *cred = v->a_cred;
  393         struct thread *td = curthread;
  394 
  395         int error;
  396 
  397         MPASS(VOP_ISLOCKED(vp));
  398 
  399         error = 0;
  400 
  401         /* Abort if any unsettable attribute is given. */
  402         if (vap->va_type != VNON ||
  403             vap->va_nlink != VNOVAL ||
  404             vap->va_fsid != VNOVAL ||
  405             vap->va_fileid != VNOVAL ||
  406             vap->va_blocksize != VNOVAL ||
  407             vap->va_gen != VNOVAL ||
  408             vap->va_rdev != VNOVAL ||
  409             vap->va_bytes != VNOVAL)
  410                 error = EINVAL;
  411 
  412         if (error == 0 && (vap->va_flags != VNOVAL))
  413                 error = tmpfs_chflags(vp, vap->va_flags, cred, td);
  414 
  415         if (error == 0 && (vap->va_size != VNOVAL))
  416                 error = tmpfs_chsize(vp, vap->va_size, cred, td);
  417 
  418         if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
  419                 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
  420 
  421         if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
  422                 error = tmpfs_chmod(vp, vap->va_mode, cred, td);
  423 
  424         if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
  425             vap->va_atime.tv_nsec != VNOVAL) ||
  426             (vap->va_mtime.tv_sec != VNOVAL &&
  427             vap->va_mtime.tv_nsec != VNOVAL) ||
  428             (vap->va_birthtime.tv_sec != VNOVAL &&
  429             vap->va_birthtime.tv_nsec != VNOVAL)))
  430                 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
  431                         &vap->va_birthtime, vap->va_vaflags, cred, td);
  432 
  433         /* Update the node times.  We give preference to the error codes
  434          * generated by this function rather than the ones that may arise
  435          * from tmpfs_update. */
  436         tmpfs_update(vp);
  437 
  438         MPASS(VOP_ISLOCKED(vp));
  439 
  440         return error;
  441 }
  442 
  443 /* --------------------------------------------------------------------- */
  444 static int
  445 tmpfs_nocacheread(vm_object_t tobj, vm_pindex_t idx,
  446     vm_offset_t offset, size_t tlen, struct uio *uio)
  447 {
  448         vm_page_t       m;
  449         int             error, rv;
  450 
  451         VM_OBJECT_LOCK(tobj);
  452         m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
  453             VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
  454         if (m->valid != VM_PAGE_BITS_ALL) {
  455                 if (vm_pager_has_page(tobj, idx, NULL, NULL)) {
  456                         rv = vm_pager_get_pages(tobj, &m, 1, 0);
  457                         if (rv != VM_PAGER_OK) {
  458                                 vm_page_lock(m);
  459                                 vm_page_free(m);
  460                                 vm_page_unlock(m);
  461                                 VM_OBJECT_UNLOCK(tobj);
  462                                 return (EIO);
  463                         }
  464                 } else
  465                         vm_page_zero_invalid(m, TRUE);
  466         }
  467         VM_OBJECT_UNLOCK(tobj);
  468         error = uiomove_fromphys(&m, offset, tlen, uio);
  469         VM_OBJECT_LOCK(tobj);
  470         vm_page_lock(m);
  471         vm_page_unwire(m, TRUE);
  472         vm_page_unlock(m);
  473         vm_page_wakeup(m);
  474         VM_OBJECT_UNLOCK(tobj);
  475 
  476         return (error);
  477 }
  478 
  479 static __inline int
  480 tmpfs_nocacheread_buf(vm_object_t tobj, vm_pindex_t idx,
  481     vm_offset_t offset, size_t tlen, void *buf)
  482 {
  483         struct uio uio;
  484         struct iovec iov;
  485 
  486         uio.uio_iovcnt = 1;
  487         uio.uio_iov = &iov;
  488         iov.iov_base = buf;
  489         iov.iov_len = tlen;
  490 
  491         uio.uio_offset = 0;
  492         uio.uio_resid = tlen;
  493         uio.uio_rw = UIO_READ;
  494         uio.uio_segflg = UIO_SYSSPACE;
  495         uio.uio_td = curthread;
  496 
  497         return (tmpfs_nocacheread(tobj, idx, offset, tlen, &uio));
  498 }
  499 
  500 static int
  501 tmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
  502 {
  503         struct sf_buf   *sf;
  504         vm_pindex_t     idx;
  505         vm_page_t       m;
  506         vm_offset_t     offset;
  507         off_t           addr;
  508         size_t          tlen;
  509         char            *ma;
  510         int             error;
  511 
  512         addr = uio->uio_offset;
  513         idx = OFF_TO_IDX(addr);
  514         offset = addr & PAGE_MASK;
  515         tlen = MIN(PAGE_SIZE - offset, len);
  516 
  517         if ((vobj == NULL) ||
  518             (vobj->resident_page_count == 0 && vobj->cache == NULL))
  519                 goto nocache;
  520 
  521         VM_OBJECT_LOCK(vobj);
  522 lookupvpg:
  523         if (((m = vm_page_lookup(vobj, idx)) != NULL) &&
  524             vm_page_is_valid(m, offset, tlen)) {
  525                 if ((m->oflags & VPO_BUSY) != 0) {
  526                         /*
  527                          * Reference the page before unlocking and sleeping so
  528                          * that the page daemon is less likely to reclaim it.  
  529                          */
  530                         vm_page_reference(m);
  531                         vm_page_sleep(m, "tmfsmr");
  532                         goto lookupvpg;
  533                 }
  534                 vm_page_busy(m);
  535                 VM_OBJECT_UNLOCK(vobj);
  536                 error = uiomove_fromphys(&m, offset, tlen, uio);
  537                 VM_OBJECT_LOCK(vobj);
  538                 vm_page_wakeup(m);
  539                 VM_OBJECT_UNLOCK(vobj);
  540                 return  (error);
  541         } else if (m != NULL && uio->uio_segflg == UIO_NOCOPY) {
  542                 KASSERT(offset == 0,
  543                     ("unexpected offset in tmpfs_mappedread for sendfile"));
  544                 if ((m->oflags & VPO_BUSY) != 0) {
  545                         /*
  546                          * Reference the page before unlocking and sleeping so
  547                          * that the page daemon is less likely to reclaim it.  
  548                          */
  549                         vm_page_reference(m);
  550                         vm_page_sleep(m, "tmfsmr");
  551                         goto lookupvpg;
  552                 }
  553                 vm_page_busy(m);
  554                 VM_OBJECT_UNLOCK(vobj);
  555                 sched_pin();
  556                 sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
  557                 ma = (char *)sf_buf_kva(sf);
  558                 error = tmpfs_nocacheread_buf(tobj, idx, 0, tlen, ma);
  559                 if (error == 0) {
  560                         if (tlen != PAGE_SIZE)
  561                                 bzero(ma + tlen, PAGE_SIZE - tlen);
  562                         uio->uio_offset += tlen;
  563                         uio->uio_resid -= tlen;
  564                 }
  565                 sf_buf_free(sf);
  566                 sched_unpin();
  567                 VM_OBJECT_LOCK(vobj);
  568                 if (error == 0)
  569                         m->valid = VM_PAGE_BITS_ALL;
  570                 vm_page_wakeup(m);
  571                 VM_OBJECT_UNLOCK(vobj);
  572                 return  (error);
  573         }
  574         VM_OBJECT_UNLOCK(vobj);
  575 nocache:
  576         error = tmpfs_nocacheread(tobj, idx, offset, tlen, uio);
  577 
  578         return  (error);
  579 }
  580 
  581 static int
  582 tmpfs_read(struct vop_read_args *v)
  583 {
  584         struct vnode *vp = v->a_vp;
  585         struct uio *uio = v->a_uio;
  586 
  587         struct tmpfs_node *node;
  588         vm_object_t uobj;
  589         size_t len;
  590         int resid;
  591 
  592         int error = 0;
  593 
  594         node = VP_TO_TMPFS_NODE(vp);
  595 
  596         if (vp->v_type != VREG) {
  597                 error = EISDIR;
  598                 goto out;
  599         }
  600 
  601         if (uio->uio_offset < 0) {
  602                 error = EINVAL;
  603                 goto out;
  604         }
  605 
  606         node->tn_status |= TMPFS_NODE_ACCESSED;
  607 
  608         uobj = node->tn_reg.tn_aobj;
  609         while ((resid = uio->uio_resid) > 0) {
  610                 error = 0;
  611                 if (node->tn_size <= uio->uio_offset)
  612                         break;
  613                 len = MIN(node->tn_size - uio->uio_offset, resid);
  614                 if (len == 0)
  615                         break;
  616                 error = tmpfs_mappedread(vp->v_object, uobj, len, uio);
  617                 if ((error != 0) || (resid == uio->uio_resid))
  618                         break;
  619         }
  620 
  621 out:
  622 
  623         return error;
  624 }
  625 
  626 /* --------------------------------------------------------------------- */
  627 
  628 static int
  629 tmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
  630 {
  631         vm_pindex_t     idx;
  632         vm_page_t       vpg, tpg;
  633         vm_offset_t     offset;
  634         off_t           addr;
  635         size_t          tlen;
  636         int             error, rv;
  637 
  638         error = 0;
  639         
  640         addr = uio->uio_offset;
  641         idx = OFF_TO_IDX(addr);
  642         offset = addr & PAGE_MASK;
  643         tlen = MIN(PAGE_SIZE - offset, len);
  644 
  645         if ((vobj == NULL) ||
  646             (vobj->resident_page_count == 0 && vobj->cache == NULL)) {
  647                 vpg = NULL;
  648                 goto nocache;
  649         }
  650 
  651         VM_OBJECT_LOCK(vobj);
  652 lookupvpg:
  653         if (((vpg = vm_page_lookup(vobj, idx)) != NULL) &&
  654             vm_page_is_valid(vpg, offset, tlen)) {
  655                 if ((vpg->oflags & VPO_BUSY) != 0) {
  656                         /*
  657                          * Reference the page before unlocking and sleeping so
  658                          * that the page daemon is less likely to reclaim it.  
  659                          */
  660                         vm_page_reference(vpg);
  661                         vm_page_sleep(vpg, "tmfsmw");
  662                         goto lookupvpg;
  663                 }
  664                 vm_page_busy(vpg);
  665                 vm_page_undirty(vpg);
  666                 VM_OBJECT_UNLOCK(vobj);
  667                 error = uiomove_fromphys(&vpg, offset, tlen, uio);
  668         } else {
  669                 if (__predict_false(vobj->cache != NULL))
  670                         vm_page_cache_free(vobj, idx, idx + 1);
  671                 VM_OBJECT_UNLOCK(vobj);
  672                 vpg = NULL;
  673         }
  674 nocache:
  675         VM_OBJECT_LOCK(tobj);
  676         tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
  677             VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
  678         if (tpg->valid != VM_PAGE_BITS_ALL) {
  679                 if (vm_pager_has_page(tobj, idx, NULL, NULL)) {
  680                         rv = vm_pager_get_pages(tobj, &tpg, 1, 0);
  681                         if (rv != VM_PAGER_OK) {
  682                                 vm_page_lock(tpg);
  683                                 vm_page_free(tpg);
  684                                 vm_page_unlock(tpg);
  685                                 error = EIO;
  686                                 goto out;
  687                         }
  688                 } else
  689                         vm_page_zero_invalid(tpg, TRUE);
  690         }
  691         VM_OBJECT_UNLOCK(tobj);
  692         if (vpg == NULL)
  693                 error = uiomove_fromphys(&tpg, offset, tlen, uio);
  694         else {
  695                 KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid"));
  696                 pmap_copy_page(vpg, tpg);
  697         }
  698         VM_OBJECT_LOCK(tobj);
  699         if (error == 0) {
  700                 KASSERT(tpg->valid == VM_PAGE_BITS_ALL,
  701                     ("parts of tpg invalid"));
  702                 vm_page_dirty(tpg);
  703         }
  704         vm_page_lock(tpg);
  705         vm_page_unwire(tpg, TRUE);
  706         vm_page_unlock(tpg);
  707         vm_page_wakeup(tpg);
  708 out:
  709         VM_OBJECT_UNLOCK(tobj);
  710         if (vpg != NULL) {
  711                 VM_OBJECT_LOCK(vobj);
  712                 vm_page_wakeup(vpg);
  713                 VM_OBJECT_UNLOCK(vobj);
  714         }
  715 
  716         return  (error);
  717 }
  718 
  719 static int
  720 tmpfs_write(struct vop_write_args *v)
  721 {
  722         struct vnode *vp = v->a_vp;
  723         struct uio *uio = v->a_uio;
  724         int ioflag = v->a_ioflag;
  725 
  726         boolean_t extended;
  727         int error = 0;
  728         off_t oldsize;
  729         struct tmpfs_node *node;
  730         vm_object_t uobj;
  731         size_t len;
  732         int resid;
  733 
  734         node = VP_TO_TMPFS_NODE(vp);
  735         oldsize = node->tn_size;
  736 
  737         if (uio->uio_offset < 0 || vp->v_type != VREG) {
  738                 error = EINVAL;
  739                 goto out;
  740         }
  741 
  742         if (uio->uio_resid == 0) {
  743                 error = 0;
  744                 goto out;
  745         }
  746 
  747         if (ioflag & IO_APPEND)
  748                 uio->uio_offset = node->tn_size;
  749 
  750         if (uio->uio_offset + uio->uio_resid >
  751           VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
  752                 return (EFBIG);
  753 
  754         if (vn_rlimit_fsize(vp, uio, uio->uio_td))
  755                 return (EFBIG);
  756 
  757         extended = uio->uio_offset + uio->uio_resid > node->tn_size;
  758         if (extended) {
  759                 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
  760                     FALSE);
  761                 if (error != 0)
  762                         goto out;
  763         }
  764 
  765         uobj = node->tn_reg.tn_aobj;
  766         while ((resid = uio->uio_resid) > 0) {
  767                 if (node->tn_size <= uio->uio_offset)
  768                         break;
  769                 len = MIN(node->tn_size - uio->uio_offset, resid);
  770                 if (len == 0)
  771                         break;
  772                 error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio);
  773                 if ((error != 0) || (resid == uio->uio_resid))
  774                         break;
  775         }
  776 
  777         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
  778             (extended ? TMPFS_NODE_CHANGED : 0);
  779 
  780         if (node->tn_mode & (S_ISUID | S_ISGID)) {
  781                 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
  782                         node->tn_mode &= ~(S_ISUID | S_ISGID);
  783         }
  784 
  785         if (error != 0)
  786                 (void)tmpfs_reg_resize(vp, oldsize, TRUE);
  787 
  788 out:
  789         MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
  790         MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
  791 
  792         return error;
  793 }
  794 
  795 /* --------------------------------------------------------------------- */
  796 
  797 static int
  798 tmpfs_fsync(struct vop_fsync_args *v)
  799 {
  800         struct vnode *vp = v->a_vp;
  801 
  802         MPASS(VOP_ISLOCKED(vp));
  803 
  804         tmpfs_update(vp);
  805 
  806         return 0;
  807 }
  808 
  809 /* --------------------------------------------------------------------- */
  810 
  811 static int
  812 tmpfs_remove(struct vop_remove_args *v)
  813 {
  814         struct vnode *dvp = v->a_dvp;
  815         struct vnode *vp = v->a_vp;
  816 
  817         int error;
  818         struct tmpfs_dirent *de;
  819         struct tmpfs_mount *tmp;
  820         struct tmpfs_node *dnode;
  821         struct tmpfs_node *node;
  822 
  823         MPASS(VOP_ISLOCKED(dvp));
  824         MPASS(VOP_ISLOCKED(vp));
  825 
  826         if (vp->v_type == VDIR) {
  827                 error = EISDIR;
  828                 goto out;
  829         }
  830 
  831         dnode = VP_TO_TMPFS_DIR(dvp);
  832         node = VP_TO_TMPFS_NODE(vp);
  833         tmp = VFS_TO_TMPFS(vp->v_mount);
  834         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
  835         MPASS(de != NULL);
  836 
  837         /* Files marked as immutable or append-only cannot be deleted. */
  838         if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
  839             (dnode->tn_flags & APPEND)) {
  840                 error = EPERM;
  841                 goto out;
  842         }
  843 
  844         /* Remove the entry from the directory; as it is a file, we do not
  845          * have to change the number of hard links of the directory. */
  846         tmpfs_dir_detach(dvp, de);
  847         if (v->a_cnp->cn_flags & DOWHITEOUT)
  848                 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
  849 
  850         /* Free the directory entry we just deleted.  Note that the node
  851          * referred by it will not be removed until the vnode is really
  852          * reclaimed. */
  853         tmpfs_free_dirent(tmp, de, TRUE);
  854 
  855         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
  856         error = 0;
  857 
  858 out:
  859 
  860         return error;
  861 }
  862 
  863 /* --------------------------------------------------------------------- */
  864 
  865 static int
  866 tmpfs_link(struct vop_link_args *v)
  867 {
  868         struct vnode *dvp = v->a_tdvp;
  869         struct vnode *vp = v->a_vp;
  870         struct componentname *cnp = v->a_cnp;
  871 
  872         int error;
  873         struct tmpfs_dirent *de;
  874         struct tmpfs_node *node;
  875 
  876         MPASS(VOP_ISLOCKED(dvp));
  877         MPASS(cnp->cn_flags & HASBUF);
  878         MPASS(dvp != vp); /* XXX When can this be false? */
  879 
  880         node = VP_TO_TMPFS_NODE(vp);
  881 
  882         /* XXX: Why aren't the following two tests done by the caller? */
  883 
  884         /* Hard links of directories are forbidden. */
  885         if (vp->v_type == VDIR) {
  886                 error = EPERM;
  887                 goto out;
  888         }
  889 
  890         /* Cannot create cross-device links. */
  891         if (dvp->v_mount != vp->v_mount) {
  892                 error = EXDEV;
  893                 goto out;
  894         }
  895 
  896         /* Ensure that we do not overflow the maximum number of links imposed
  897          * by the system. */
  898         MPASS(node->tn_links <= LINK_MAX);
  899         if (node->tn_links == LINK_MAX) {
  900                 error = EMLINK;
  901                 goto out;
  902         }
  903 
  904         /* We cannot create links of files marked immutable or append-only. */
  905         if (node->tn_flags & (IMMUTABLE | APPEND)) {
  906                 error = EPERM;
  907                 goto out;
  908         }
  909 
  910         /* Allocate a new directory entry to represent the node. */
  911         error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
  912             cnp->cn_nameptr, cnp->cn_namelen, &de);
  913         if (error != 0)
  914                 goto out;
  915 
  916         /* Insert the new directory entry into the appropriate directory. */
  917         if (cnp->cn_flags & ISWHITEOUT)
  918                 tmpfs_dir_whiteout_remove(dvp, cnp);
  919         tmpfs_dir_attach(dvp, de);
  920 
  921         /* vp link count has changed, so update node times. */
  922         node->tn_status |= TMPFS_NODE_CHANGED;
  923         tmpfs_update(vp);
  924 
  925         error = 0;
  926 
  927 out:
  928         return error;
  929 }
  930 
  931 /* --------------------------------------------------------------------- */
  932 
  933 /*
  934  * We acquire all but fdvp locks using non-blocking acquisitions.  If we
  935  * fail to acquire any lock in the path we will drop all held locks,
  936  * acquire the new lock in a blocking fashion, and then release it and
  937  * restart the rename.  This acquire/release step ensures that we do not
  938  * spin on a lock waiting for release.  On error release all vnode locks
  939  * and decrement references the way tmpfs_rename() would do.
  940  */
  941 static int
  942 tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp,
  943     struct vnode *tdvp, struct vnode **tvpp,
  944     struct componentname *fcnp, struct componentname *tcnp)
  945 {
  946         struct vnode *nvp;
  947         struct mount *mp;
  948         struct tmpfs_dirent *de;
  949         int error, restarts = 0;
  950 
  951         VOP_UNLOCK(tdvp, 0);
  952         if (*tvpp != NULL && *tvpp != tdvp)
  953                 VOP_UNLOCK(*tvpp, 0);
  954         mp = fdvp->v_mount;
  955 
  956 relock:
  957         restarts += 1;
  958         error = vn_lock(fdvp, LK_EXCLUSIVE);
  959         if (error)
  960                 goto releout;
  961         if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
  962                 VOP_UNLOCK(fdvp, 0);
  963                 error = vn_lock(tdvp, LK_EXCLUSIVE);
  964                 if (error)
  965                         goto releout;
  966                 VOP_UNLOCK(tdvp, 0);
  967                 goto relock;
  968         }
  969         /*
  970          * Re-resolve fvp to be certain it still exists and fetch the
  971          * correct vnode.
  972          */
  973         de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp);
  974         if (de == NULL) {
  975                 VOP_UNLOCK(fdvp, 0);
  976                 VOP_UNLOCK(tdvp, 0);
  977                 if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
  978                     (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
  979                         error = EINVAL;
  980                 else
  981                         error = ENOENT;
  982                 goto releout;
  983         }
  984         error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp);
  985         if (error != 0) {
  986                 VOP_UNLOCK(fdvp, 0);
  987                 VOP_UNLOCK(tdvp, 0);
  988                 if (error != EBUSY)
  989                         goto releout;
  990                 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp);
  991                 if (error != 0)
  992                         goto releout;
  993                 VOP_UNLOCK(nvp, 0);
  994                 /*
  995                  * Concurrent rename race.
  996                  */
  997                 if (nvp == tdvp) {
  998                         vrele(nvp);
  999                         error = EINVAL;
 1000                         goto releout;
 1001                 }
 1002                 vrele(*fvpp);
 1003                 *fvpp = nvp;
 1004                 goto relock;
 1005         }
 1006         vrele(*fvpp);
 1007         *fvpp = nvp;
 1008         VOP_UNLOCK(*fvpp, 0);
 1009         /*
 1010          * Re-resolve tvp and acquire the vnode lock if present.
 1011          */
 1012         de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp);
 1013         /*
 1014          * If tvp disappeared we just carry on.
 1015          */
 1016         if (de == NULL && *tvpp != NULL) {
 1017                 vrele(*tvpp);
 1018                 *tvpp = NULL;
 1019         }
 1020         /*
 1021          * Get the tvp ino if the lookup succeeded.  We may have to restart
 1022          * if the non-blocking acquire fails.
 1023          */
 1024         if (de != NULL) {
 1025                 nvp = NULL;
 1026                 error = tmpfs_alloc_vp(mp, de->td_node,
 1027                     LK_EXCLUSIVE | LK_NOWAIT, &nvp);
 1028                 if (*tvpp != NULL)
 1029                         vrele(*tvpp);
 1030                 *tvpp = nvp;
 1031                 if (error != 0) {
 1032                         VOP_UNLOCK(fdvp, 0);
 1033                         VOP_UNLOCK(tdvp, 0);
 1034                         if (error != EBUSY)
 1035                                 goto releout;
 1036                         error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE,
 1037                             &nvp);
 1038                         if (error != 0)
 1039                                 goto releout;
 1040                         VOP_UNLOCK(nvp, 0);
 1041                         /*
 1042                          * fdvp contains fvp, thus tvp (=fdvp) is not empty.
 1043                          */
 1044                         if (nvp == fdvp) {
 1045                                 error = ENOTEMPTY;
 1046                                 goto releout;
 1047                         }
 1048                         goto relock;
 1049                 }
 1050         }
 1051         tmpfs_rename_restarts += restarts;
 1052 
 1053         return (0);
 1054 
 1055 releout:
 1056         vrele(fdvp);
 1057         vrele(*fvpp);
 1058         vrele(tdvp);
 1059         if (*tvpp != NULL)
 1060                 vrele(*tvpp);
 1061         tmpfs_rename_restarts += restarts;
 1062 
 1063         return (error);
 1064 }
 1065 
 1066 static int
 1067 tmpfs_rename(struct vop_rename_args *v)
 1068 {
 1069         struct vnode *fdvp = v->a_fdvp;
 1070         struct vnode *fvp = v->a_fvp;
 1071         struct componentname *fcnp = v->a_fcnp;
 1072         struct vnode *tdvp = v->a_tdvp;
 1073         struct vnode *tvp = v->a_tvp;
 1074         struct componentname *tcnp = v->a_tcnp;
 1075         struct mount *mp = NULL;
 1076 
 1077         char *newname;
 1078         int error;
 1079         struct tmpfs_dirent *de;
 1080         struct tmpfs_mount *tmp;
 1081         struct tmpfs_node *fdnode;
 1082         struct tmpfs_node *fnode;
 1083         struct tmpfs_node *tnode;
 1084         struct tmpfs_node *tdnode;
 1085 
 1086         MPASS(VOP_ISLOCKED(tdvp));
 1087         MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
 1088         MPASS(fcnp->cn_flags & HASBUF);
 1089         MPASS(tcnp->cn_flags & HASBUF);
 1090 
 1091         /* Disallow cross-device renames.
 1092          * XXX Why isn't this done by the caller? */
 1093         if (fvp->v_mount != tdvp->v_mount ||
 1094             (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
 1095                 error = EXDEV;
 1096                 goto out;
 1097         }
 1098 
 1099         /* If source and target are the same file, there is nothing to do. */
 1100         if (fvp == tvp) {
 1101                 error = 0;
 1102                 goto out;
 1103         }
 1104 
 1105         /* If we need to move the directory between entries, lock the
 1106          * source so that we can safely operate on it. */
 1107         if (fdvp != tdvp && fdvp != tvp) {
 1108                 if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
 1109                         mp = tdvp->v_mount;
 1110                         error = vfs_busy(mp, 0);
 1111                         if (error != 0) {
 1112                                 mp = NULL;
 1113                                 goto out;
 1114                         }
 1115                         error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp,
 1116                             fcnp, tcnp);
 1117                         if (error != 0) {
 1118                                 vfs_unbusy(mp);
 1119                                 return (error);
 1120                         }
 1121                         ASSERT_VOP_ELOCKED(fdvp,
 1122                             "tmpfs_rename: fdvp not locked");
 1123                         ASSERT_VOP_ELOCKED(tdvp,
 1124                             "tmpfs_rename: tdvp not locked");
 1125                         if (tvp != NULL)
 1126                                 ASSERT_VOP_ELOCKED(tvp,
 1127                                     "tmpfs_rename: tvp not locked");
 1128                         if (fvp == tvp) {
 1129                                 error = 0;
 1130                                 goto out_locked;
 1131                         }
 1132                 }
 1133         }
 1134 
 1135         tmp = VFS_TO_TMPFS(tdvp->v_mount);
 1136         tdnode = VP_TO_TMPFS_DIR(tdvp);
 1137         tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
 1138         fdnode = VP_TO_TMPFS_DIR(fdvp);
 1139         fnode = VP_TO_TMPFS_NODE(fvp);
 1140         de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
 1141 
 1142         /* Entry can disappear before we lock fdvp,
 1143          * also avoid manipulating '.' and '..' entries. */
 1144         if (de == NULL) {
 1145                 if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
 1146                     (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
 1147                         error = EINVAL;
 1148                 else
 1149                         error = ENOENT;
 1150                 goto out_locked;
 1151         }
 1152         MPASS(de->td_node == fnode);
 1153 
 1154         /* If re-naming a directory to another preexisting directory
 1155          * ensure that the target directory is empty so that its
 1156          * removal causes no side effects.
 1157          * Kern_rename gurantees the destination to be a directory
 1158          * if the source is one. */
 1159         if (tvp != NULL) {
 1160                 MPASS(tnode != NULL);
 1161 
 1162                 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
 1163                     (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
 1164                         error = EPERM;
 1165                         goto out_locked;
 1166                 }
 1167 
 1168                 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
 1169                         if (tnode->tn_size > 0) {
 1170                                 error = ENOTEMPTY;
 1171                                 goto out_locked;
 1172                         }
 1173                 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
 1174                         error = ENOTDIR;
 1175                         goto out_locked;
 1176                 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
 1177                         error = EISDIR;
 1178                         goto out_locked;
 1179                 } else {
 1180                         MPASS(fnode->tn_type != VDIR &&
 1181                                 tnode->tn_type != VDIR);
 1182                 }
 1183         }
 1184 
 1185         if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
 1186             || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
 1187                 error = EPERM;
 1188                 goto out_locked;
 1189         }
 1190 
 1191         /* Ensure that we have enough memory to hold the new name, if it
 1192          * has to be changed. */
 1193         if (fcnp->cn_namelen != tcnp->cn_namelen ||
 1194             bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
 1195                 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
 1196         } else
 1197                 newname = NULL;
 1198 
 1199         /* If the node is being moved to another directory, we have to do
 1200          * the move. */
 1201         if (fdnode != tdnode) {
 1202                 /* In case we are moving a directory, we have to adjust its
 1203                  * parent to point to the new parent. */
 1204                 if (de->td_node->tn_type == VDIR) {
 1205                         struct tmpfs_node *n;
 1206 
 1207                         /* Ensure the target directory is not a child of the
 1208                          * directory being moved.  Otherwise, we'd end up
 1209                          * with stale nodes. */
 1210                         n = tdnode;
 1211                         /* TMPFS_LOCK garanties that no nodes are freed while
 1212                          * traversing the list. Nodes can only be marked as
 1213                          * removed: tn_parent == NULL. */
 1214                         TMPFS_LOCK(tmp);
 1215                         TMPFS_NODE_LOCK(n);
 1216                         while (n != n->tn_dir.tn_parent) {
 1217                                 struct tmpfs_node *parent;
 1218 
 1219                                 if (n == fnode) {
 1220                                         TMPFS_NODE_UNLOCK(n);
 1221                                         TMPFS_UNLOCK(tmp);
 1222                                         error = EINVAL;
 1223                                         if (newname != NULL)
 1224                                                     free(newname, M_TMPFSNAME);
 1225                                         goto out_locked;
 1226                                 }
 1227                                 parent = n->tn_dir.tn_parent;
 1228                                 TMPFS_NODE_UNLOCK(n);
 1229                                 if (parent == NULL) {
 1230                                         n = NULL;
 1231                                         break;
 1232                                 }
 1233                                 TMPFS_NODE_LOCK(parent);
 1234                                 if (parent->tn_dir.tn_parent == NULL) {
 1235                                         TMPFS_NODE_UNLOCK(parent);
 1236                                         n = NULL;
 1237                                         break;
 1238                                 }
 1239                                 n = parent;
 1240                         }
 1241                         TMPFS_UNLOCK(tmp);
 1242                         if (n == NULL) {
 1243                                 error = EINVAL;
 1244                                 if (newname != NULL)
 1245                                             free(newname, M_TMPFSNAME);
 1246                                 goto out_locked;
 1247                         }
 1248                         TMPFS_NODE_UNLOCK(n);
 1249 
 1250                         /* Adjust the parent pointer. */
 1251                         TMPFS_VALIDATE_DIR(fnode);
 1252                         TMPFS_NODE_LOCK(de->td_node);
 1253                         de->td_node->tn_dir.tn_parent = tdnode;
 1254                         TMPFS_NODE_UNLOCK(de->td_node);
 1255 
 1256                         /* As a result of changing the target of the '..'
 1257                          * entry, the link count of the source and target
 1258                          * directories has to be adjusted. */
 1259                         TMPFS_NODE_LOCK(tdnode);
 1260                         TMPFS_ASSERT_LOCKED(tdnode);
 1261                         tdnode->tn_links++;
 1262                         TMPFS_NODE_UNLOCK(tdnode);
 1263 
 1264                         TMPFS_NODE_LOCK(fdnode);
 1265                         TMPFS_ASSERT_LOCKED(fdnode);
 1266                         fdnode->tn_links--;
 1267                         TMPFS_NODE_UNLOCK(fdnode);
 1268                 }
 1269 
 1270                 /* Do the move: just remove the entry from the source directory
 1271                  * and insert it into the target one. */
 1272                 tmpfs_dir_detach(fdvp, de);
 1273                 if (fcnp->cn_flags & DOWHITEOUT)
 1274                         tmpfs_dir_whiteout_add(fdvp, fcnp);
 1275                 if (tcnp->cn_flags & ISWHITEOUT)
 1276                         tmpfs_dir_whiteout_remove(tdvp, tcnp);
 1277                 tmpfs_dir_attach(tdvp, de);
 1278         }
 1279 
 1280         /* If the name has changed, we need to make it effective by changing
 1281          * it in the directory entry. */
 1282         if (newname != NULL) {
 1283                 MPASS(tcnp->cn_namelen <= MAXNAMLEN);
 1284 
 1285                 free(de->td_name, M_TMPFSNAME);
 1286                 de->td_namelen = (uint16_t)tcnp->cn_namelen;
 1287                 memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
 1288                 de->td_name = newname;
 1289 
 1290                 fnode->tn_status |= TMPFS_NODE_CHANGED;
 1291                 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
 1292         }
 1293 
 1294         /* If we are overwriting an entry, we have to remove the old one
 1295          * from the target directory. */
 1296         if (tvp != NULL) {
 1297                 /* Remove the old entry from the target directory. */
 1298                 de = tmpfs_dir_lookup(tdnode, tnode, tcnp);
 1299                 tmpfs_dir_detach(tdvp, de);
 1300 
 1301                 /* Free the directory entry we just deleted.  Note that the
 1302                  * node referred by it will not be removed until the vnode is
 1303                  * really reclaimed. */
 1304                 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE);
 1305         }
 1306         cache_purge(fvp);
 1307         if (tvp != NULL)
 1308                 cache_purge(tvp);
 1309         cache_purge_negative(tdvp);
 1310 
 1311         error = 0;
 1312 
 1313 out_locked:
 1314         if (fdvp != tdvp && fdvp != tvp)
 1315                 VOP_UNLOCK(fdvp, 0);
 1316 
 1317 out:
 1318         /* Release target nodes. */
 1319         /* XXX: I don't understand when tdvp can be the same as tvp, but
 1320          * other code takes care of this... */
 1321         if (tdvp == tvp)
 1322                 vrele(tdvp);
 1323         else
 1324                 vput(tdvp);
 1325         if (tvp != NULL)
 1326                 vput(tvp);
 1327 
 1328         /* Release source nodes. */
 1329         vrele(fdvp);
 1330         vrele(fvp);
 1331 
 1332         if (mp != NULL)
 1333                 vfs_unbusy(mp);
 1334 
 1335         return error;
 1336 }
 1337 
 1338 /* --------------------------------------------------------------------- */
 1339 
 1340 static int
 1341 tmpfs_mkdir(struct vop_mkdir_args *v)
 1342 {
 1343         struct vnode *dvp = v->a_dvp;
 1344         struct vnode **vpp = v->a_vpp;
 1345         struct componentname *cnp = v->a_cnp;
 1346         struct vattr *vap = v->a_vap;
 1347 
 1348         MPASS(vap->va_type == VDIR);
 1349 
 1350         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 1351 }
 1352 
 1353 /* --------------------------------------------------------------------- */
 1354 
 1355 static int
 1356 tmpfs_rmdir(struct vop_rmdir_args *v)
 1357 {
 1358         struct vnode *dvp = v->a_dvp;
 1359         struct vnode *vp = v->a_vp;
 1360 
 1361         int error;
 1362         struct tmpfs_dirent *de;
 1363         struct tmpfs_mount *tmp;
 1364         struct tmpfs_node *dnode;
 1365         struct tmpfs_node *node;
 1366 
 1367         MPASS(VOP_ISLOCKED(dvp));
 1368         MPASS(VOP_ISLOCKED(vp));
 1369 
 1370         tmp = VFS_TO_TMPFS(dvp->v_mount);
 1371         dnode = VP_TO_TMPFS_DIR(dvp);
 1372         node = VP_TO_TMPFS_DIR(vp);
 1373 
 1374         /* Directories with more than two entries ('.' and '..') cannot be
 1375          * removed. */
 1376          if (node->tn_size > 0) {
 1377                  error = ENOTEMPTY;
 1378                  goto out;
 1379          }
 1380 
 1381         if ((dnode->tn_flags & APPEND)
 1382             || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
 1383                 error = EPERM;
 1384                 goto out;
 1385         }
 1386 
 1387         /* This invariant holds only if we are not trying to remove "..".
 1388           * We checked for that above so this is safe now. */
 1389         MPASS(node->tn_dir.tn_parent == dnode);
 1390 
 1391         /* Get the directory entry associated with node (vp).  This was
 1392          * filled by tmpfs_lookup while looking up the entry. */
 1393         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
 1394         MPASS(TMPFS_DIRENT_MATCHES(de,
 1395             v->a_cnp->cn_nameptr,
 1396             v->a_cnp->cn_namelen));
 1397 
 1398         /* Check flags to see if we are allowed to remove the directory. */
 1399         if (dnode->tn_flags & APPEND
 1400                 || node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
 1401                 error = EPERM;
 1402                 goto out;
 1403         }
 1404 
 1405 
 1406         /* Detach the directory entry from the directory (dnode). */
 1407         tmpfs_dir_detach(dvp, de);
 1408         if (v->a_cnp->cn_flags & DOWHITEOUT)
 1409                 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
 1410 
 1411         /* No vnode should be allocated for this entry from this point */
 1412         TMPFS_NODE_LOCK(node);
 1413         TMPFS_ASSERT_ELOCKED(node);
 1414         node->tn_links--;
 1415         node->tn_dir.tn_parent = NULL;
 1416         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
 1417             TMPFS_NODE_MODIFIED;
 1418 
 1419         TMPFS_NODE_UNLOCK(node);
 1420 
 1421         TMPFS_NODE_LOCK(dnode);
 1422         TMPFS_ASSERT_ELOCKED(dnode);
 1423         dnode->tn_links--;
 1424         dnode->tn_status |= TMPFS_NODE_ACCESSED | \
 1425             TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
 1426         TMPFS_NODE_UNLOCK(dnode);
 1427 
 1428         cache_purge(dvp);
 1429         cache_purge(vp);
 1430 
 1431         /* Free the directory entry we just deleted.  Note that the node
 1432          * referred by it will not be removed until the vnode is really
 1433          * reclaimed. */
 1434         tmpfs_free_dirent(tmp, de, TRUE);
 1435 
 1436         /* Release the deleted vnode (will destroy the node, notify
 1437          * interested parties and clean it from the cache). */
 1438 
 1439         dnode->tn_status |= TMPFS_NODE_CHANGED;
 1440         tmpfs_update(dvp);
 1441 
 1442         error = 0;
 1443 
 1444 out:
 1445         return error;
 1446 }
 1447 
 1448 /* --------------------------------------------------------------------- */
 1449 
 1450 static int
 1451 tmpfs_symlink(struct vop_symlink_args *v)
 1452 {
 1453         struct vnode *dvp = v->a_dvp;
 1454         struct vnode **vpp = v->a_vpp;
 1455         struct componentname *cnp = v->a_cnp;
 1456         struct vattr *vap = v->a_vap;
 1457         char *target = v->a_target;
 1458 
 1459 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
 1460         MPASS(vap->va_type == VLNK);
 1461 #else
 1462         vap->va_type = VLNK;
 1463 #endif
 1464 
 1465         return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
 1466 }
 1467 
 1468 /* --------------------------------------------------------------------- */
 1469 
 1470 static int
 1471 tmpfs_readdir(struct vop_readdir_args *v)
 1472 {
 1473         struct vnode *vp = v->a_vp;
 1474         struct uio *uio = v->a_uio;
 1475         int *eofflag = v->a_eofflag;
 1476         u_long **cookies = v->a_cookies;
 1477         int *ncookies = v->a_ncookies;
 1478 
 1479         int error;
 1480         off_t startoff;
 1481         off_t cnt = 0;
 1482         struct tmpfs_node *node;
 1483 
 1484         /* This operation only makes sense on directory nodes. */
 1485         if (vp->v_type != VDIR)
 1486                 return ENOTDIR;
 1487 
 1488         node = VP_TO_TMPFS_DIR(vp);
 1489 
 1490         startoff = uio->uio_offset;
 1491 
 1492         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
 1493                 error = tmpfs_dir_getdotdent(node, uio);
 1494                 if (error != 0)
 1495                         goto outok;
 1496                 cnt++;
 1497         }
 1498 
 1499         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
 1500                 error = tmpfs_dir_getdotdotdent(node, uio);
 1501                 if (error != 0)
 1502                         goto outok;
 1503                 cnt++;
 1504         }
 1505 
 1506         error = tmpfs_dir_getdents(node, uio, &cnt);
 1507 
 1508 outok:
 1509         MPASS(error >= -1);
 1510 
 1511         if (error == -1)
 1512                 error = (cnt != 0) ? 0 : EINVAL;
 1513 
 1514         if (eofflag != NULL)
 1515                 *eofflag =
 1516                     (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
 1517 
 1518         /* Update NFS-related variables. */
 1519         if (error == 0 && cookies != NULL && ncookies != NULL) {
 1520                 off_t i;
 1521                 off_t off = startoff;
 1522                 struct tmpfs_dirent *de = NULL;
 1523 
 1524                 *ncookies = cnt;
 1525                 *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
 1526 
 1527                 for (i = 0; i < cnt; i++) {
 1528                         MPASS(off != TMPFS_DIRCOOKIE_EOF);
 1529                         if (off == TMPFS_DIRCOOKIE_DOT) {
 1530                                 off = TMPFS_DIRCOOKIE_DOTDOT;
 1531                         } else {
 1532                                 if (off == TMPFS_DIRCOOKIE_DOTDOT) {
 1533                                         de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
 1534                                 } else if (de != NULL) {
 1535                                         de = TAILQ_NEXT(de, td_entries);
 1536                                 } else {
 1537                                         de = tmpfs_dir_lookupbycookie(node,
 1538                                             off);
 1539                                         MPASS(de != NULL);
 1540                                         de = TAILQ_NEXT(de, td_entries);
 1541                                 }
 1542                                 if (de == NULL)
 1543                                         off = TMPFS_DIRCOOKIE_EOF;
 1544                                 else
 1545                                         off = tmpfs_dircookie(de);
 1546                         }
 1547 
 1548                         (*cookies)[i] = off;
 1549                 }
 1550                 MPASS(uio->uio_offset == off);
 1551         }
 1552 
 1553         return error;
 1554 }
 1555 
 1556 /* --------------------------------------------------------------------- */
 1557 
 1558 static int
 1559 tmpfs_readlink(struct vop_readlink_args *v)
 1560 {
 1561         struct vnode *vp = v->a_vp;
 1562         struct uio *uio = v->a_uio;
 1563 
 1564         int error;
 1565         struct tmpfs_node *node;
 1566 
 1567         MPASS(uio->uio_offset == 0);
 1568         MPASS(vp->v_type == VLNK);
 1569 
 1570         node = VP_TO_TMPFS_NODE(vp);
 1571 
 1572         error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
 1573             uio);
 1574         node->tn_status |= TMPFS_NODE_ACCESSED;
 1575 
 1576         return error;
 1577 }
 1578 
 1579 /* --------------------------------------------------------------------- */
 1580 
 1581 static int
 1582 tmpfs_inactive(struct vop_inactive_args *v)
 1583 {
 1584         struct vnode *vp = v->a_vp;
 1585         struct thread *l = v->a_td;
 1586 
 1587         struct tmpfs_node *node;
 1588 
 1589         MPASS(VOP_ISLOCKED(vp));
 1590 
 1591         node = VP_TO_TMPFS_NODE(vp);
 1592 
 1593         if (node->tn_links == 0)
 1594                 vrecycle(vp, l);
 1595 
 1596         return 0;
 1597 }
 1598 
 1599 /* --------------------------------------------------------------------- */
 1600 
 1601 int
 1602 tmpfs_reclaim(struct vop_reclaim_args *v)
 1603 {
 1604         struct vnode *vp = v->a_vp;
 1605 
 1606         struct tmpfs_mount *tmp;
 1607         struct tmpfs_node *node;
 1608 
 1609         node = VP_TO_TMPFS_NODE(vp);
 1610         tmp = VFS_TO_TMPFS(vp->v_mount);
 1611 
 1612         vnode_destroy_vobject(vp);
 1613         cache_purge(vp);
 1614 
 1615         TMPFS_NODE_LOCK(node);
 1616         TMPFS_ASSERT_ELOCKED(node);
 1617         tmpfs_free_vp(vp);
 1618 
 1619         /* If the node referenced by this vnode was deleted by the user,
 1620          * we must free its associated data structures (now that the vnode
 1621          * is being reclaimed). */
 1622         if (node->tn_links == 0 &&
 1623             (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) {
 1624                 node->tn_vpstate = TMPFS_VNODE_DOOMED;
 1625                 TMPFS_NODE_UNLOCK(node);
 1626                 tmpfs_free_node(tmp, node);
 1627         } else
 1628                 TMPFS_NODE_UNLOCK(node);
 1629 
 1630         MPASS(vp->v_data == NULL);
 1631         return 0;
 1632 }
 1633 
 1634 /* --------------------------------------------------------------------- */
 1635 
 1636 static int
 1637 tmpfs_print(struct vop_print_args *v)
 1638 {
 1639         struct vnode *vp = v->a_vp;
 1640 
 1641         struct tmpfs_node *node;
 1642 
 1643         node = VP_TO_TMPFS_NODE(vp);
 1644 
 1645         printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
 1646             node, node->tn_flags, node->tn_links);
 1647         printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX
 1648             ", status 0x%x\n",
 1649             node->tn_mode, node->tn_uid, node->tn_gid,
 1650             (uintmax_t)node->tn_size, node->tn_status);
 1651 
 1652         if (vp->v_type == VFIFO)
 1653                 fifo_printinfo(vp);
 1654 
 1655         printf("\n");
 1656 
 1657         return 0;
 1658 }
 1659 
 1660 /* --------------------------------------------------------------------- */
 1661 
 1662 static int
 1663 tmpfs_pathconf(struct vop_pathconf_args *v)
 1664 {
 1665         int name = v->a_name;
 1666         register_t *retval = v->a_retval;
 1667 
 1668         int error;
 1669 
 1670         error = 0;
 1671 
 1672         switch (name) {
 1673         case _PC_LINK_MAX:
 1674                 *retval = LINK_MAX;
 1675                 break;
 1676 
 1677         case _PC_NAME_MAX:
 1678                 *retval = NAME_MAX;
 1679                 break;
 1680 
 1681         case _PC_PATH_MAX:
 1682                 *retval = PATH_MAX;
 1683                 break;
 1684 
 1685         case _PC_PIPE_BUF:
 1686                 *retval = PIPE_BUF;
 1687                 break;
 1688 
 1689         case _PC_CHOWN_RESTRICTED:
 1690                 *retval = 1;
 1691                 break;
 1692 
 1693         case _PC_NO_TRUNC:
 1694                 *retval = 1;
 1695                 break;
 1696 
 1697         case _PC_SYNC_IO:
 1698                 *retval = 1;
 1699                 break;
 1700 
 1701         case _PC_FILESIZEBITS:
 1702                 *retval = 0; /* XXX Don't know which value should I return. */
 1703                 break;
 1704 
 1705         default:
 1706                 error = EINVAL;
 1707         }
 1708 
 1709         return error;
 1710 }
 1711 
 1712 static int
 1713 tmpfs_vptofh(struct vop_vptofh_args *ap)
 1714 {
 1715         struct tmpfs_fid *tfhp;
 1716         struct tmpfs_node *node;
 1717 
 1718         tfhp = (struct tmpfs_fid *)ap->a_fhp;
 1719         node = VP_TO_TMPFS_NODE(ap->a_vp);
 1720 
 1721         tfhp->tf_len = sizeof(struct tmpfs_fid);
 1722         tfhp->tf_id = node->tn_id;
 1723         tfhp->tf_gen = node->tn_gen;
 1724 
 1725         return (0);
 1726 }
 1727 
 1728 static int
 1729 tmpfs_whiteout(struct vop_whiteout_args *ap)
 1730 {
 1731         struct vnode *dvp = ap->a_dvp;
 1732         struct componentname *cnp = ap->a_cnp;
 1733         struct tmpfs_dirent *de;
 1734 
 1735         switch (ap->a_flags) {
 1736         case LOOKUP:
 1737                 return (0);
 1738         case CREATE:
 1739                 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
 1740                 if (de != NULL)
 1741                         return (de->td_node == NULL ? 0 : EEXIST);
 1742                 return (tmpfs_dir_whiteout_add(dvp, cnp));
 1743         case DELETE:
 1744                 tmpfs_dir_whiteout_remove(dvp, cnp);
 1745                 return (0);
 1746         default:
 1747                 panic("tmpfs_whiteout: unknown op");
 1748         }
 1749 }
 1750 
 1751 /* --------------------------------------------------------------------- */
 1752 
 1753 /*
 1754  * vnode operations vector used for files stored in a tmpfs file system.
 1755  */
 1756 struct vop_vector tmpfs_vnodeop_entries = {
 1757         .vop_default =                  &default_vnodeops,
 1758         .vop_lookup =                   vfs_cache_lookup,
 1759         .vop_cachedlookup =             tmpfs_lookup,
 1760         .vop_create =                   tmpfs_create,
 1761         .vop_mknod =                    tmpfs_mknod,
 1762         .vop_open =                     tmpfs_open,
 1763         .vop_close =                    tmpfs_close,
 1764         .vop_access =                   tmpfs_access,
 1765         .vop_getattr =                  tmpfs_getattr,
 1766         .vop_setattr =                  tmpfs_setattr,
 1767         .vop_read =                     tmpfs_read,
 1768         .vop_write =                    tmpfs_write,
 1769         .vop_fsync =                    tmpfs_fsync,
 1770         .vop_remove =                   tmpfs_remove,
 1771         .vop_link =                     tmpfs_link,
 1772         .vop_rename =                   tmpfs_rename,
 1773         .vop_mkdir =                    tmpfs_mkdir,
 1774         .vop_rmdir =                    tmpfs_rmdir,
 1775         .vop_symlink =                  tmpfs_symlink,
 1776         .vop_readdir =                  tmpfs_readdir,
 1777         .vop_readlink =                 tmpfs_readlink,
 1778         .vop_inactive =                 tmpfs_inactive,
 1779         .vop_reclaim =                  tmpfs_reclaim,
 1780         .vop_print =                    tmpfs_print,
 1781         .vop_pathconf =                 tmpfs_pathconf,
 1782         .vop_vptofh =                   tmpfs_vptofh,
 1783         .vop_whiteout =                 tmpfs_whiteout,
 1784         .vop_bmap =                     VOP_EOPNOTSUPP,
 1785 };
 1786 

Cache object: bac01607caebe65d4e5d15c840608015


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