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/resourcevar.h>
   46 #include <sys/stat.h>
   47 #include <sys/systm.h>
   48 #include <sys/unistd.h>
   49 #include <sys/vnode.h>
   50 
   51 #include <vm/vm.h>
   52 #include <vm/vm_object.h>
   53 #include <vm/vm_page.h>
   54 #include <vm/vm_pager.h>
   55 #include <sys/sched.h>
   56 #include <sys/sf_buf.h>
   57 #include <machine/_inttypes.h>
   58 
   59 #include <fs/fifofs/fifo.h>
   60 #include <fs/tmpfs/tmpfs_vnops.h>
   61 #include <fs/tmpfs/tmpfs.h>
   62 
   63 /* --------------------------------------------------------------------- */
   64 
   65 static int
   66 tmpfs_lookup(struct vop_cachedlookup_args *v)
   67 {
   68         struct vnode *dvp = v->a_dvp;
   69         struct vnode **vpp = v->a_vpp;
   70         struct componentname *cnp = v->a_cnp;
   71         struct thread *td = cnp->cn_thread;
   72 
   73         int error;
   74         struct tmpfs_dirent *de;
   75         struct tmpfs_node *dnode;
   76 
   77         dnode = VP_TO_TMPFS_DIR(dvp);
   78         *vpp = NULLVP;
   79 
   80         /* Check accessibility of requested node as a first step. */
   81         error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
   82         if (error != 0)
   83                 goto out;
   84 
   85         /* We cannot be requesting the parent directory of the root node. */
   86         MPASS(IMPLIES(dnode->tn_type == VDIR &&
   87             dnode->tn_dir.tn_parent == dnode,
   88             !(cnp->cn_flags & ISDOTDOT)));
   89 
   90         if (cnp->cn_flags & ISDOTDOT) {
   91                 int ltype = 0;
   92 
   93                 ltype = VOP_ISLOCKED(dvp, td);
   94                 vhold(dvp);
   95                 VOP_UNLOCK(dvp, 0, td);
   96                 /* Allocate a new vnode on the matching entry. */
   97                 error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
   98                     cnp->cn_lkflags, vpp, td);
   99 
  100                 vn_lock(dvp, ltype | LK_RETRY, td);
  101                 vdrop(dvp);
  102         } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
  103                 VREF(dvp);
  104                 *vpp = dvp;
  105                 error = 0;
  106         } else {
  107                 de = tmpfs_dir_lookup(dnode, NULL, cnp);
  108                 if (de == NULL) {
  109                         /* The entry was not found in the directory.
  110                          * This is OK if we are creating or renaming an
  111                          * entry and are working on the last component of
  112                          * the path name. */
  113                         if ((cnp->cn_flags & ISLASTCN) &&
  114                             (cnp->cn_nameiop == CREATE || \
  115                             cnp->cn_nameiop == RENAME)) {
  116                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
  117                                     cnp->cn_thread);
  118                                 if (error != 0)
  119                                         goto out;
  120 
  121                                 /* Keep the component name in the buffer for
  122                                  * future uses. */
  123                                 cnp->cn_flags |= SAVENAME;
  124 
  125                                 error = EJUSTRETURN;
  126                         } else
  127                                 error = ENOENT;
  128                 } else {
  129                         struct tmpfs_node *tnode;
  130 
  131                         /* The entry was found, so get its associated
  132                          * tmpfs_node. */
  133                         tnode = de->td_node;
  134 
  135                         /* If we are not at the last path component and
  136                          * found a non-directory or non-link entry (which
  137                          * may itself be pointing to a directory), raise
  138                          * an error. */
  139                         if ((tnode->tn_type != VDIR &&
  140                             tnode->tn_type != VLNK) &&
  141                             !(cnp->cn_flags & ISLASTCN)) {
  142                                 error = ENOTDIR;
  143                                 goto out;
  144                         }
  145 
  146                         /* If we are deleting or renaming the entry, keep
  147                          * track of its tmpfs_dirent so that it can be
  148                          * easily deleted later. */
  149                         if ((cnp->cn_flags & ISLASTCN) &&
  150                             (cnp->cn_nameiop == DELETE ||
  151                             cnp->cn_nameiop == RENAME)) {
  152                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
  153                                     cnp->cn_thread);
  154                                 if (error != 0)
  155                                         goto out;
  156 
  157                                 /* Allocate a new vnode on the matching entry. */
  158                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
  159                                                 cnp->cn_lkflags, vpp, td);
  160                                 if (error != 0)
  161                                         goto out;
  162 
  163                                 if ((dnode->tn_mode & S_ISTXT) &&
  164                                   VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) &&
  165                                   VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) {
  166                                         error = EPERM;
  167                                         vput(*vpp);
  168                                         *vpp = NULL;
  169                                         goto out;
  170                                 }
  171                                 cnp->cn_flags |= SAVENAME;
  172                         } else {
  173                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
  174                                                 cnp->cn_lkflags, vpp, td);
  175                         }
  176                 }
  177         }
  178 
  179         /* Store the result of this lookup in the cache.  Avoid this if the
  180          * request was for creation, as it does not improve timings on
  181          * emprical tests. */
  182         if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
  183                 cache_enter(dvp, *vpp, cnp);
  184 
  185 out:
  186         /* If there were no errors, *vpp cannot be null and it must be
  187          * locked. */
  188         MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp, td)));
  189 
  190         return error;
  191 }
  192 
  193 /* --------------------------------------------------------------------- */
  194 
  195 static int
  196 tmpfs_create(struct vop_create_args *v)
  197 {
  198         struct vnode *dvp = v->a_dvp;
  199         struct vnode **vpp = v->a_vpp;
  200         struct componentname *cnp = v->a_cnp;
  201         struct vattr *vap = v->a_vap;
  202 
  203         MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
  204 
  205         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
  206 }
  207 /* --------------------------------------------------------------------- */
  208 
  209 static int
  210 tmpfs_mknod(struct vop_mknod_args *v)
  211 {
  212         struct vnode *dvp = v->a_dvp;
  213         struct vnode **vpp = v->a_vpp;
  214         struct componentname *cnp = v->a_cnp;
  215         struct vattr *vap = v->a_vap;
  216 
  217         if (vap->va_type != VBLK && vap->va_type != VCHR &&
  218             vap->va_type != VFIFO)
  219                 return EINVAL;
  220 
  221         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
  222 }
  223 
  224 /* --------------------------------------------------------------------- */
  225 
  226 static int
  227 tmpfs_open(struct vop_open_args *v)
  228 {
  229         struct vnode *vp = v->a_vp;
  230         int mode = v->a_mode;
  231 
  232         int error;
  233         struct tmpfs_node *node;
  234 
  235         MPASS(VOP_ISLOCKED(vp, v->a_td));
  236 
  237         node = VP_TO_TMPFS_NODE(vp);
  238 
  239         /* The file is still active but all its names have been removed
  240          * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
  241          * it is about to die. */
  242         if (node->tn_links < 1)
  243                 return (ENOENT);
  244 
  245         /* If the file is marked append-only, deny write requests. */
  246         if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
  247                 error = EPERM;
  248         else {
  249                 error = 0;
  250                 vnode_create_vobject(vp, node->tn_size, v->a_td);
  251         }
  252 
  253         MPASS(VOP_ISLOCKED(vp, v->a_td));
  254         return error;
  255 }
  256 
  257 /* --------------------------------------------------------------------- */
  258 
  259 static int
  260 tmpfs_close(struct vop_close_args *v)
  261 {
  262         struct vnode *vp = v->a_vp;
  263 
  264         struct tmpfs_node *node;
  265 
  266         MPASS(VOP_ISLOCKED(vp, v->a_td));
  267 
  268         node = VP_TO_TMPFS_NODE(vp);
  269 
  270         if (node->tn_links > 0) {
  271                 /* Update node times.  No need to do it if the node has
  272                  * been deleted, because it will vanish after we return. */
  273                 tmpfs_update(vp);
  274         }
  275 
  276         return 0;
  277 }
  278 
  279 /* --------------------------------------------------------------------- */
  280 
  281 int
  282 tmpfs_access(struct vop_access_args *v)
  283 {
  284         struct vnode *vp = v->a_vp;
  285         int mode = v->a_mode;
  286         struct ucred *cred = v->a_cred;
  287 
  288         int error;
  289         struct tmpfs_node *node;
  290 
  291         MPASS(VOP_ISLOCKED(vp, v->a_td));
  292 
  293         node = VP_TO_TMPFS_NODE(vp);
  294 
  295         switch (vp->v_type) {
  296         case VDIR:
  297                 /* FALLTHROUGH */
  298         case VLNK:
  299                 /* FALLTHROUGH */
  300         case VREG:
  301                 if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
  302                         error = EROFS;
  303                         goto out;
  304                 }
  305                 break;
  306 
  307         case VBLK:
  308                 /* FALLTHROUGH */
  309         case VCHR:
  310                 /* FALLTHROUGH */
  311         case VSOCK:
  312                 /* FALLTHROUGH */
  313         case VFIFO:
  314                 break;
  315 
  316         default:
  317                 error = EINVAL;
  318                 goto out;
  319         }
  320 
  321         if (mode & VWRITE && node->tn_flags & IMMUTABLE) {
  322                 error = EPERM;
  323                 goto out;
  324         }
  325 
  326         error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
  327             node->tn_gid, mode, cred, NULL);
  328 
  329 out:
  330         MPASS(VOP_ISLOCKED(vp, v->a_td));
  331 
  332         return error;
  333 }
  334 
  335 /* --------------------------------------------------------------------- */
  336 
  337 int
  338 tmpfs_getattr(struct vop_getattr_args *v)
  339 {
  340         struct vnode *vp = v->a_vp;
  341         struct vattr *vap = v->a_vap;
  342 
  343         struct tmpfs_node *node;
  344 
  345         node = VP_TO_TMPFS_NODE(vp);
  346 
  347         tmpfs_update(vp);
  348 
  349         vap->va_type = vp->v_type;
  350         vap->va_mode = node->tn_mode;
  351         vap->va_nlink = node->tn_links;
  352         vap->va_uid = node->tn_uid;
  353         vap->va_gid = node->tn_gid;
  354         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  355         vap->va_fileid = node->tn_id;
  356         vap->va_size = node->tn_size;
  357         vap->va_blocksize = PAGE_SIZE;
  358         vap->va_atime = node->tn_atime;
  359         vap->va_mtime = node->tn_mtime;
  360         vap->va_ctime = node->tn_ctime;
  361         vap->va_birthtime = node->tn_birthtime;
  362         vap->va_gen = node->tn_gen;
  363         vap->va_flags = node->tn_flags;
  364         vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
  365                 node->tn_rdev : NODEV;
  366         vap->va_bytes = round_page(node->tn_size);
  367         vap->va_filerev = 0;
  368 
  369         return 0;
  370 }
  371 
  372 /* --------------------------------------------------------------------- */
  373 
  374 /* XXX Should this operation be atomic?  I think it should, but code in
  375  * XXX other places (e.g., ufs) doesn't seem to be... */
  376 int
  377 tmpfs_setattr(struct vop_setattr_args *v)
  378 {
  379         struct vnode *vp = v->a_vp;
  380         struct vattr *vap = v->a_vap;
  381         struct ucred *cred = v->a_cred;
  382         struct thread *l = v->a_td;
  383 
  384         int error;
  385 
  386         MPASS(VOP_ISLOCKED(vp, l));
  387 
  388         error = 0;
  389 
  390         /* Abort if any unsettable attribute is given. */
  391         if (vap->va_type != VNON ||
  392             vap->va_nlink != VNOVAL ||
  393             vap->va_fsid != VNOVAL ||
  394             vap->va_fileid != VNOVAL ||
  395             vap->va_blocksize != VNOVAL ||
  396             vap->va_gen != VNOVAL ||
  397             vap->va_rdev != VNOVAL ||
  398             vap->va_bytes != VNOVAL)
  399                 error = EINVAL;
  400 
  401         if (error == 0 && (vap->va_flags != VNOVAL))
  402                 error = tmpfs_chflags(vp, vap->va_flags, cred, l);
  403 
  404         if (error == 0 && (vap->va_size != VNOVAL))
  405                 error = tmpfs_chsize(vp, vap->va_size, cred, l);
  406 
  407         if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
  408                 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred,
  409                     l);
  410 
  411         if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
  412                 error = tmpfs_chmod(vp, vap->va_mode, cred, l);
  413 
  414         if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
  415             vap->va_atime.tv_nsec != VNOVAL) ||
  416             (vap->va_mtime.tv_sec != VNOVAL &&
  417             vap->va_mtime.tv_nsec != VNOVAL) ||
  418             (vap->va_birthtime.tv_sec != VNOVAL &&
  419             vap->va_birthtime.tv_nsec != VNOVAL)))
  420                 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
  421                         &vap->va_birthtime, vap->va_vaflags, cred, l);
  422 
  423         /* Update the node times.  We give preference to the error codes
  424          * generated by this function rather than the ones that may arise
  425          * from tmpfs_update. */
  426         tmpfs_update(vp);
  427 
  428         MPASS(VOP_ISLOCKED(vp, l));
  429 
  430         return error;
  431 }
  432 
  433 /* --------------------------------------------------------------------- */
  434 
  435 static int
  436 tmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
  437 {
  438         vm_pindex_t     idx;
  439         vm_page_t       m;
  440         struct sf_buf   *sf;
  441         off_t           offset, addr;
  442         size_t          tlen;
  443         caddr_t         va;
  444         int             error;
  445 
  446         addr = uio->uio_offset;
  447         idx = OFF_TO_IDX(addr);
  448         offset = addr & PAGE_MASK;
  449         tlen = MIN(PAGE_SIZE - offset, len);
  450 
  451         if ((vobj == NULL) || (vobj->resident_page_count == 0))
  452                 goto nocache;
  453 
  454         VM_OBJECT_LOCK(vobj);
  455 lookupvpg:
  456         if (((m = vm_page_lookup(vobj, idx)) != NULL) &&
  457             vm_page_is_valid(m, offset, tlen)) {
  458                 if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr"))
  459                         goto lookupvpg;
  460                 vm_page_busy(m);
  461                 VM_OBJECT_UNLOCK(vobj);
  462                 sched_pin();
  463                 sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
  464                 va = (caddr_t)sf_buf_kva(sf);
  465                 error = uiomove(va + offset, tlen, uio);
  466                 sf_buf_free(sf);
  467                 sched_unpin();
  468                 VM_OBJECT_LOCK(vobj);
  469                 vm_page_wakeup(m);
  470                 VM_OBJECT_UNLOCK(vobj);
  471                 return  (error);
  472         }
  473         VM_OBJECT_UNLOCK(vobj);
  474 nocache:
  475         VM_OBJECT_LOCK(tobj);
  476         vm_object_pip_add(tobj, 1);
  477         m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
  478             VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
  479         if (m->valid != VM_PAGE_BITS_ALL) {
  480                 int behind, ahead;
  481                 if (vm_pager_has_page(tobj, idx, &behind, &ahead)) {
  482                         error = vm_pager_get_pages(tobj, &m, 1, 0);
  483                         if (error != 0) {
  484                                 printf("tmpfs get pages from pager error [read]\n");
  485                                 goto out;
  486                         }
  487                 } else
  488                         vm_page_zero_invalid(m, TRUE);
  489         }
  490         VM_OBJECT_UNLOCK(tobj);
  491         sched_pin();
  492         sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
  493         va = (caddr_t)sf_buf_kva(sf);
  494         error = uiomove(va + offset, tlen, uio);
  495         sf_buf_free(sf);
  496         sched_unpin();
  497         VM_OBJECT_LOCK(tobj);
  498 out:
  499         vm_page_lock_queues();
  500         vm_page_unwire(m, 0);
  501         vm_page_activate(m);
  502         vm_page_unlock_queues();
  503         vm_page_wakeup(m);
  504         vm_object_pip_subtract(tobj, 1);
  505         VM_OBJECT_UNLOCK(tobj);
  506 
  507         return  (error);
  508 }
  509 
  510 static int
  511 tmpfs_read(struct vop_read_args *v)
  512 {
  513         struct vnode *vp = v->a_vp;
  514         struct uio *uio = v->a_uio;
  515 
  516         struct tmpfs_node *node;
  517         vm_object_t uobj;
  518         size_t len;
  519         int resid;
  520 
  521         int error;
  522 
  523         node = VP_TO_TMPFS_NODE(vp);
  524 
  525         if (vp->v_type != VREG) {
  526                 error = EISDIR;
  527                 goto out;
  528         }
  529 
  530         if (uio->uio_offset < 0) {
  531                 error = EINVAL;
  532                 goto out;
  533         }
  534 
  535         node->tn_status |= TMPFS_NODE_ACCESSED;
  536 
  537         uobj = node->tn_reg.tn_aobj;
  538         while ((resid = uio->uio_resid) > 0) {
  539                 error = 0;
  540                 if (node->tn_size <= uio->uio_offset)
  541                         break;
  542                 len = MIN(node->tn_size - uio->uio_offset, resid);
  543                 if (len == 0)
  544                         break;
  545                 error = tmpfs_mappedread(vp->v_object, uobj, len, uio);
  546                 if ((error != 0) || (resid == uio->uio_resid))
  547                         break;
  548         }
  549 
  550 out:
  551 
  552         return error;
  553 }
  554 
  555 /* --------------------------------------------------------------------- */
  556 
  557 static int
  558 tmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
  559 {
  560         vm_pindex_t     idx;
  561         vm_page_t       vpg, tpg;
  562         struct sf_buf   *sf;
  563         off_t           offset, addr;
  564         size_t          tlen;
  565         caddr_t         va;
  566         int             error;
  567 
  568         addr = uio->uio_offset;
  569         idx = OFF_TO_IDX(addr);
  570         offset = addr & PAGE_MASK;
  571         tlen = MIN(PAGE_SIZE - offset, len);
  572 
  573         if ((vobj == NULL) || (vobj->resident_page_count == 0)) {
  574                 vpg = NULL;
  575                 goto nocache;
  576         }
  577 
  578         VM_OBJECT_LOCK(vobj);
  579 lookupvpg:
  580         if (((vpg = vm_page_lookup(vobj, idx)) != NULL) &&
  581             vm_page_is_valid(vpg, offset, tlen)) {
  582                 if (vm_page_sleep_if_busy(vpg, FALSE, "tmfsmw"))
  583                         goto lookupvpg;
  584                 vm_page_busy(vpg);
  585                 vm_page_lock_queues();
  586                 vm_page_undirty(vpg);
  587                 vm_page_unlock_queues();
  588                 VM_OBJECT_UNLOCK(vobj);
  589                 sched_pin();
  590                 sf = sf_buf_alloc(vpg, SFB_CPUPRIVATE);
  591                 va = (caddr_t)sf_buf_kva(sf);
  592                 error = uiomove(va + offset, tlen, uio);
  593                 sf_buf_free(sf);
  594                 sched_unpin();
  595         } else {
  596                 VM_OBJECT_UNLOCK(vobj);
  597                 vpg = NULL;
  598         }
  599 nocache:
  600         VM_OBJECT_LOCK(tobj);
  601         vm_object_pip_add(tobj, 1);
  602         tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
  603             VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
  604         if (tpg->valid != VM_PAGE_BITS_ALL) {
  605                 int behind, ahead;
  606                 if (vm_pager_has_page(tobj, idx, &behind, &ahead)) {
  607                         error = vm_pager_get_pages(tobj, &tpg, 1, 0);
  608                         if (error != 0) {
  609                                 printf("tmpfs get pages from pager error [write]\n");
  610                                 goto out;
  611                         }
  612                 } else
  613                         vm_page_zero_invalid(tpg, TRUE);
  614         }
  615         VM_OBJECT_UNLOCK(tobj);
  616         if (vpg == NULL) {
  617                 sched_pin();
  618                 sf = sf_buf_alloc(tpg, SFB_CPUPRIVATE);
  619                 va = (caddr_t)sf_buf_kva(sf);
  620                 error = uiomove(va + offset, tlen, uio);
  621                 sf_buf_free(sf);
  622                 sched_unpin();
  623         } else {
  624                 KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid"));
  625                 pmap_copy_page(vpg, tpg);
  626         }
  627         VM_OBJECT_LOCK(tobj);
  628 out:
  629         if (vobj != NULL)
  630                 VM_OBJECT_LOCK(vobj);
  631         vm_page_lock_queues();
  632         if (error == 0) {
  633                 vm_page_set_validclean(tpg, offset, tlen);
  634                 vm_page_zero_invalid(tpg, TRUE);
  635                 vm_page_dirty(tpg);
  636         }
  637         vm_page_unwire(tpg, 0);
  638         vm_page_activate(tpg);
  639         vm_page_unlock_queues();
  640         vm_page_wakeup(tpg);
  641         if (vpg != NULL)
  642                 vm_page_wakeup(vpg);
  643         if (vobj != NULL)
  644                 VM_OBJECT_UNLOCK(vobj);
  645         vm_object_pip_subtract(tobj, 1);
  646         VM_OBJECT_UNLOCK(tobj);
  647 
  648         return  (error);
  649 }
  650 
  651 static int
  652 tmpfs_write(struct vop_write_args *v)
  653 {
  654         struct vnode *vp = v->a_vp;
  655         struct uio *uio = v->a_uio;
  656         int ioflag = v->a_ioflag;
  657         struct thread *td = uio->uio_td;
  658 
  659         boolean_t extended;
  660         int error = 0;
  661         off_t oldsize;
  662         struct tmpfs_node *node;
  663         vm_object_t uobj;
  664         size_t len;
  665         int resid;
  666 
  667         node = VP_TO_TMPFS_NODE(vp);
  668         oldsize = node->tn_size;
  669 
  670         if (uio->uio_offset < 0 || vp->v_type != VREG) {
  671                 error = EINVAL;
  672                 goto out;
  673         }
  674 
  675         if (uio->uio_resid == 0) {
  676                 error = 0;
  677                 goto out;
  678         }
  679 
  680         if (ioflag & IO_APPEND)
  681                 uio->uio_offset = node->tn_size;
  682 
  683         if (uio->uio_offset + uio->uio_resid >
  684           VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
  685                 return (EFBIG);
  686 
  687         if (vp->v_type == VREG && td != NULL) {
  688                 PROC_LOCK(td->td_proc);
  689                 if (uio->uio_offset + uio->uio_resid >
  690                   lim_cur(td->td_proc, RLIMIT_FSIZE)) {
  691                         psignal(td->td_proc, SIGXFSZ);
  692                         PROC_UNLOCK(td->td_proc);
  693                         return (EFBIG);
  694                 }
  695                 PROC_UNLOCK(td->td_proc);
  696         }
  697 
  698         extended = uio->uio_offset + uio->uio_resid > node->tn_size;
  699         if (extended) {
  700                 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
  701                 if (error != 0)
  702                         goto out;
  703         }
  704 
  705         uobj = node->tn_reg.tn_aobj;
  706         while ((resid = uio->uio_resid) > 0) {
  707                 if (node->tn_size <= uio->uio_offset)
  708                         break;
  709                 len = MIN(node->tn_size - uio->uio_offset, resid);
  710                 if (len == 0)
  711                         break;
  712                 error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio);
  713                 if ((error != 0) || (resid == uio->uio_resid))
  714                         break;
  715         }
  716 
  717         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
  718             (extended ? TMPFS_NODE_CHANGED : 0);
  719 
  720         if (node->tn_mode & (S_ISUID | S_ISGID)) {
  721                 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
  722                         node->tn_mode &= ~(S_ISUID | S_ISGID);
  723         }
  724 
  725         if (error != 0)
  726                 (void)tmpfs_reg_resize(vp, oldsize);
  727 
  728 out:
  729         MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
  730         MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
  731 
  732         return error;
  733 }
  734 
  735 /* --------------------------------------------------------------------- */
  736 
  737 static int
  738 tmpfs_fsync(struct vop_fsync_args *v)
  739 {
  740         struct vnode *vp = v->a_vp;
  741 
  742         MPASS(VOP_ISLOCKED(vp, v->a_td));
  743 
  744         tmpfs_update(vp);
  745 
  746         return 0;
  747 }
  748 
  749 /* --------------------------------------------------------------------- */
  750 
  751 static int
  752 tmpfs_remove(struct vop_remove_args *v)
  753 {
  754         struct vnode *dvp = v->a_dvp;
  755         struct vnode *vp = v->a_vp;
  756 
  757         int error;
  758         struct tmpfs_dirent *de;
  759         struct tmpfs_mount *tmp;
  760         struct tmpfs_node *dnode;
  761         struct tmpfs_node *node;
  762 
  763         MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread));
  764         MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread));
  765 
  766         if (vp->v_type == VDIR) {
  767                 error = EISDIR;
  768                 goto out;
  769         }
  770 
  771         dnode = VP_TO_TMPFS_DIR(dvp);
  772         node = VP_TO_TMPFS_NODE(vp);
  773         tmp = VFS_TO_TMPFS(vp->v_mount);
  774         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
  775         MPASS(de != NULL);
  776 
  777         /* Files marked as immutable or append-only cannot be deleted. */
  778         if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
  779             (dnode->tn_flags & APPEND)) {
  780                 error = EPERM;
  781                 goto out;
  782         }
  783 
  784         /* Remove the entry from the directory; as it is a file, we do not
  785          * have to change the number of hard links of the directory. */
  786         tmpfs_dir_detach(dvp, de);
  787 
  788         /* Free the directory entry we just deleted.  Note that the node
  789          * referred by it will not be removed until the vnode is really
  790          * reclaimed. */
  791         tmpfs_free_dirent(tmp, de, TRUE);
  792 
  793         if (node->tn_links > 0)
  794                 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
  795         error = 0;
  796 
  797 out:
  798 
  799         return error;
  800 }
  801 
  802 /* --------------------------------------------------------------------- */
  803 
  804 static int
  805 tmpfs_link(struct vop_link_args *v)
  806 {
  807         struct vnode *dvp = v->a_tdvp;
  808         struct vnode *vp = v->a_vp;
  809         struct componentname *cnp = v->a_cnp;
  810 
  811         int error;
  812         struct tmpfs_dirent *de;
  813         struct tmpfs_node *node;
  814 
  815         MPASS(VOP_ISLOCKED(dvp, cnp->cn_thread));
  816         MPASS(cnp->cn_flags & HASBUF);
  817         MPASS(dvp != vp); /* XXX When can this be false? */
  818 
  819         node = VP_TO_TMPFS_NODE(vp);
  820 
  821         /* XXX: Why aren't the following two tests done by the caller? */
  822 
  823         /* Hard links of directories are forbidden. */
  824         if (vp->v_type == VDIR) {
  825                 error = EPERM;
  826                 goto out;
  827         }
  828 
  829         /* Cannot create cross-device links. */
  830         if (dvp->v_mount != vp->v_mount) {
  831                 error = EXDEV;
  832                 goto out;
  833         }
  834 
  835         /* Ensure that we do not overflow the maximum number of links imposed
  836          * by the system. */
  837         MPASS(node->tn_links <= LINK_MAX);
  838         if (node->tn_links == LINK_MAX) {
  839                 error = EMLINK;
  840                 goto out;
  841         }
  842 
  843         /* We cannot create links of files marked immutable or append-only. */
  844         if (node->tn_flags & (IMMUTABLE | APPEND)) {
  845                 error = EPERM;
  846                 goto out;
  847         }
  848 
  849         /* Allocate a new directory entry to represent the node. */
  850         error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
  851             cnp->cn_nameptr, cnp->cn_namelen, &de);
  852         if (error != 0)
  853                 goto out;
  854 
  855         /* Insert the new directory entry into the appropriate directory. */
  856         tmpfs_dir_attach(dvp, de);
  857 
  858         /* vp link count has changed, so update node times. */
  859         node->tn_status |= TMPFS_NODE_CHANGED;
  860         tmpfs_update(vp);
  861 
  862         error = 0;
  863 
  864 out:
  865         return error;
  866 }
  867 
  868 /* --------------------------------------------------------------------- */
  869 
  870 static int
  871 tmpfs_rename(struct vop_rename_args *v)
  872 {
  873         struct vnode *fdvp = v->a_fdvp;
  874         struct vnode *fvp = v->a_fvp;
  875         struct componentname *fcnp = v->a_fcnp;
  876         struct vnode *tdvp = v->a_tdvp;
  877         struct vnode *tvp = v->a_tvp;
  878         struct componentname *tcnp = v->a_tcnp;
  879 
  880         char *newname;
  881         int error;
  882         struct tmpfs_dirent *de;
  883         struct tmpfs_node *fdnode;
  884         struct tmpfs_node *fnode;
  885         struct tmpfs_node *tnode;
  886         struct tmpfs_node *tdnode;
  887 
  888         MPASS(VOP_ISLOCKED(tdvp, tcnp->cn_thread));
  889         MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp, tcnp->cn_thread)));
  890         MPASS(fcnp->cn_flags & HASBUF);
  891         MPASS(tcnp->cn_flags & HASBUF);
  892 
  893         tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
  894 
  895         /* Disallow cross-device renames.
  896          * XXX Why isn't this done by the caller? */
  897         if (fvp->v_mount != tdvp->v_mount ||
  898             (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
  899                 error = EXDEV;
  900                 goto out;
  901         }
  902 
  903         tdnode = VP_TO_TMPFS_DIR(tdvp);
  904 
  905         /* If source and target are the same file, there is nothing to do. */
  906         if (fvp == tvp) {
  907                 error = 0;
  908                 goto out;
  909         }
  910 
  911         /* If we need to move the directory between entries, lock the
  912          * source so that we can safely operate on it. */
  913         if (tdvp != fdvp) {
  914                 error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, tcnp->cn_thread);
  915                 if (error != 0)
  916                         goto out;
  917         }
  918         fdnode = VP_TO_TMPFS_DIR(fdvp);
  919         fnode = VP_TO_TMPFS_NODE(fvp);
  920         de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
  921 
  922         /* Avoid manipulating '.' and '..' entries. */
  923         if (de == NULL) {
  924                 MPASS(fvp->v_type == VDIR);
  925                 error = EINVAL;
  926                 goto out_locked;
  927         }
  928         MPASS(de->td_node == fnode);
  929 
  930         /* If re-naming a directory to another preexisting directory
  931          * ensure that the target directory is empty so that its
  932          * removal causes no side effects.
  933          * Kern_rename gurantees the destination to be a directory
  934          * if the source is one. */
  935         if (tvp != NULL) {
  936                 MPASS(tnode != NULL);
  937 
  938                 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
  939                     (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
  940                         error = EPERM;
  941                         goto out_locked;
  942                 }
  943 
  944                 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
  945                         if (tnode->tn_size > 0) {
  946                                 error = ENOTEMPTY;
  947                                 goto out_locked;
  948                         }
  949                 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
  950                         error = ENOTDIR;
  951                         goto out_locked;
  952                 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
  953                         error = EISDIR;
  954                         goto out_locked;
  955                 } else {
  956                         MPASS(fnode->tn_type != VDIR &&
  957                                 tnode->tn_type != VDIR);
  958                 }
  959         }
  960 
  961         if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
  962             || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
  963                 error = EPERM;
  964                 goto out_locked;
  965         }
  966 
  967         /* Ensure that we have enough memory to hold the new name, if it
  968          * has to be changed. */
  969         if (fcnp->cn_namelen != tcnp->cn_namelen ||
  970             memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
  971                 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
  972         } else
  973                 newname = NULL;
  974 
  975         /* If the node is being moved to another directory, we have to do
  976          * the move. */
  977         if (fdnode != tdnode) {
  978                 /* In case we are moving a directory, we have to adjust its
  979                  * parent to point to the new parent. */
  980                 if (de->td_node->tn_type == VDIR) {
  981                         struct tmpfs_node *n;
  982 
  983                         /* Ensure the target directory is not a child of the
  984                          * directory being moved.  Otherwise, we'd end up
  985                          * with stale nodes. */
  986                         n = tdnode;
  987                         while (n != n->tn_dir.tn_parent) {
  988                                 if (n == fnode) {
  989                                         error = EINVAL;
  990                                         if (newname != NULL)
  991                                                     free(newname, M_TMPFSNAME);
  992                                         goto out_locked;
  993                                 }
  994                                 n = n->tn_dir.tn_parent;
  995                         }
  996 
  997                         /* Adjust the parent pointer. */
  998                         TMPFS_VALIDATE_DIR(fnode);
  999                         de->td_node->tn_dir.tn_parent = tdnode;
 1000 
 1001                         /* As a result of changing the target of the '..'
 1002                          * entry, the link count of the source and target
 1003                          * directories has to be adjusted. */
 1004                         fdnode->tn_links--;
 1005                         tdnode->tn_links++;
 1006                 }
 1007 
 1008                 /* Do the move: just remove the entry from the source directory
 1009                  * and insert it into the target one. */
 1010                 tmpfs_dir_detach(fdvp, de);
 1011                 tmpfs_dir_attach(tdvp, de);
 1012         }
 1013 
 1014         /* If the name has changed, we need to make it effective by changing
 1015          * it in the directory entry. */
 1016         if (newname != NULL) {
 1017                 MPASS(tcnp->cn_namelen <= MAXNAMLEN);
 1018 
 1019                 free(de->td_name, M_TMPFSNAME);
 1020                 de->td_namelen = (uint16_t)tcnp->cn_namelen;
 1021                 memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
 1022                 de->td_name = newname;
 1023 
 1024                 fnode->tn_status |= TMPFS_NODE_CHANGED;
 1025                 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
 1026         }
 1027 
 1028         /* If we are overwriting an entry, we have to remove the old one
 1029          * from the target directory. */
 1030         if (tvp != NULL) {
 1031                 /* Remove the old entry from the target directory. */
 1032                 de = tmpfs_dir_lookup(tdnode, tnode, tcnp);
 1033                 tmpfs_dir_detach(tdvp, de);
 1034 
 1035                 /* Free the directory entry we just deleted.  Note that the
 1036                  * node referred by it will not be removed until the vnode is
 1037                  * really reclaimed. */
 1038                 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE);
 1039         }
 1040 
 1041         error = 0;
 1042 
 1043 out_locked:
 1044         if (fdnode != tdnode)
 1045                 VOP_UNLOCK(fdvp, 0, tcnp->cn_thread);
 1046 
 1047 out:
 1048         /* Release target nodes. */
 1049         /* XXX: I don't understand when tdvp can be the same as tvp, but
 1050          * other code takes care of this... */
 1051         if (tdvp == tvp)
 1052                 vrele(tdvp);
 1053         else
 1054                 vput(tdvp);
 1055         if (tvp != NULL)
 1056                 vput(tvp);
 1057 
 1058         /* Release source nodes. */
 1059         vrele(fdvp);
 1060         vrele(fvp);
 1061 
 1062         return error;
 1063 }
 1064 
 1065 /* --------------------------------------------------------------------- */
 1066 
 1067 static int
 1068 tmpfs_mkdir(struct vop_mkdir_args *v)
 1069 {
 1070         struct vnode *dvp = v->a_dvp;
 1071         struct vnode **vpp = v->a_vpp;
 1072         struct componentname *cnp = v->a_cnp;
 1073         struct vattr *vap = v->a_vap;
 1074 
 1075         MPASS(vap->va_type == VDIR);
 1076 
 1077         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 1078 }
 1079 
 1080 /* --------------------------------------------------------------------- */
 1081 
 1082 static int
 1083 tmpfs_rmdir(struct vop_rmdir_args *v)
 1084 {
 1085         struct vnode *dvp = v->a_dvp;
 1086         struct vnode *vp = v->a_vp;
 1087 
 1088         int error;
 1089         struct tmpfs_dirent *de;
 1090         struct tmpfs_mount *tmp;
 1091         struct tmpfs_node *dnode;
 1092         struct tmpfs_node *node;
 1093 
 1094         MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread));
 1095         MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread));
 1096 
 1097         tmp = VFS_TO_TMPFS(dvp->v_mount);
 1098         dnode = VP_TO_TMPFS_DIR(dvp);
 1099         node = VP_TO_TMPFS_DIR(vp);
 1100 
 1101         /* Directories with more than two entries ('.' and '..') cannot be
 1102          * removed. */
 1103          if (node->tn_size > 0) {
 1104                  error = ENOTEMPTY;
 1105                  goto out;
 1106          }
 1107 
 1108         if ((dnode->tn_flags & APPEND)
 1109             || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
 1110                 error = EPERM;
 1111                 goto out;
 1112         }
 1113 
 1114         /* This invariant holds only if we are not trying to remove "..".
 1115           * We checked for that above so this is safe now. */
 1116         MPASS(node->tn_dir.tn_parent == dnode);
 1117 
 1118         /* Get the directory entry associated with node (vp).  This was
 1119          * filled by tmpfs_lookup while looking up the entry. */
 1120         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
 1121         MPASS(TMPFS_DIRENT_MATCHES(de,
 1122             v->a_cnp->cn_nameptr,
 1123             v->a_cnp->cn_namelen));
 1124 
 1125         /* Check flags to see if we are allowed to remove the directory. */
 1126         if (dnode->tn_flags & APPEND
 1127                 || node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
 1128                 error = EPERM;
 1129                 goto out;
 1130         }
 1131 
 1132         /* Detach the directory entry from the directory (dnode). */
 1133         tmpfs_dir_detach(dvp, de);
 1134 
 1135         node->tn_links--;
 1136         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
 1137             TMPFS_NODE_MODIFIED;
 1138         node->tn_dir.tn_parent->tn_links--;
 1139         node->tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \
 1140             TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
 1141 
 1142         cache_purge(dvp);
 1143         cache_purge(vp);
 1144 
 1145         /* Free the directory entry we just deleted.  Note that the node
 1146          * referred by it will not be removed until the vnode is really
 1147          * reclaimed. */
 1148         tmpfs_free_dirent(tmp, de, TRUE);
 1149 
 1150         /* Release the deleted vnode (will destroy the node, notify
 1151          * interested parties and clean it from the cache). */
 1152 
 1153         dnode->tn_status |= TMPFS_NODE_CHANGED;
 1154         tmpfs_update(dvp);
 1155 
 1156         error = 0;
 1157 
 1158 out:
 1159         return error;
 1160 }
 1161 
 1162 /* --------------------------------------------------------------------- */
 1163 
 1164 static int
 1165 tmpfs_symlink(struct vop_symlink_args *v)
 1166 {
 1167         struct vnode *dvp = v->a_dvp;
 1168         struct vnode **vpp = v->a_vpp;
 1169         struct componentname *cnp = v->a_cnp;
 1170         struct vattr *vap = v->a_vap;
 1171         char *target = v->a_target;
 1172 
 1173 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
 1174         MPASS(vap->va_type == VLNK);
 1175 #else
 1176         vap->va_type = VLNK;
 1177 #endif
 1178 
 1179         return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
 1180 }
 1181 
 1182 /* --------------------------------------------------------------------- */
 1183 
 1184 static int
 1185 tmpfs_readdir(struct vop_readdir_args *v)
 1186 {
 1187         struct vnode *vp = v->a_vp;
 1188         struct uio *uio = v->a_uio;
 1189         int *eofflag = v->a_eofflag;
 1190         u_long **cookies = v->a_cookies;
 1191         int *ncookies = v->a_ncookies;
 1192 
 1193         int error;
 1194         off_t startoff;
 1195         off_t cnt = 0;
 1196         struct tmpfs_node *node;
 1197 
 1198         /* This operation only makes sense on directory nodes. */
 1199         if (vp->v_type != VDIR)
 1200                 return ENOTDIR;
 1201 
 1202         node = VP_TO_TMPFS_DIR(vp);
 1203 
 1204         startoff = uio->uio_offset;
 1205 
 1206         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
 1207                 error = tmpfs_dir_getdotdent(node, uio);
 1208                 if (error != 0)
 1209                         goto outok;
 1210                 cnt++;
 1211         }
 1212 
 1213         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
 1214                 error = tmpfs_dir_getdotdotdent(node, uio);
 1215                 if (error != 0)
 1216                         goto outok;
 1217                 cnt++;
 1218         }
 1219 
 1220         error = tmpfs_dir_getdents(node, uio, &cnt);
 1221 
 1222 outok:
 1223         MPASS(error >= -1);
 1224 
 1225         if (error == -1)
 1226                 error = 0;
 1227 
 1228         if (eofflag != NULL)
 1229                 *eofflag =
 1230                     (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
 1231 
 1232         /* Update NFS-related variables. */
 1233         if (error == 0 && cookies != NULL && ncookies != NULL) {
 1234                 off_t i;
 1235                 off_t off = startoff;
 1236                 struct tmpfs_dirent *de = NULL;
 1237 
 1238                 *ncookies = cnt;
 1239                 *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
 1240 
 1241                 for (i = 0; i < cnt; i++) {
 1242                         MPASS(off != TMPFS_DIRCOOKIE_EOF);
 1243                         if (off == TMPFS_DIRCOOKIE_DOT) {
 1244                                 off = TMPFS_DIRCOOKIE_DOTDOT;
 1245                         } else {
 1246                                 if (off == TMPFS_DIRCOOKIE_DOTDOT) {
 1247                                         de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
 1248                                 } else if (de != NULL) {
 1249                                         de = TAILQ_NEXT(de, td_entries);
 1250                                 } else {
 1251                                         de = tmpfs_dir_lookupbycookie(node,
 1252                                             off);
 1253                                         MPASS(de != NULL);
 1254                                         de = TAILQ_NEXT(de, td_entries);
 1255                                 }
 1256                                 if (de == NULL)
 1257                                         off = TMPFS_DIRCOOKIE_EOF;
 1258                                 else
 1259                                         off = tmpfs_dircookie(de);
 1260                         }
 1261 
 1262                         (*cookies)[i] = off;
 1263                 }
 1264                 MPASS(uio->uio_offset == off);
 1265         }
 1266 
 1267         return error;
 1268 }
 1269 
 1270 /* --------------------------------------------------------------------- */
 1271 
 1272 static int
 1273 tmpfs_readlink(struct vop_readlink_args *v)
 1274 {
 1275         struct vnode *vp = v->a_vp;
 1276         struct uio *uio = v->a_uio;
 1277 
 1278         int error;
 1279         struct tmpfs_node *node;
 1280 
 1281         MPASS(uio->uio_offset == 0);
 1282         MPASS(vp->v_type == VLNK);
 1283 
 1284         node = VP_TO_TMPFS_NODE(vp);
 1285 
 1286         error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
 1287             uio);
 1288         node->tn_status |= TMPFS_NODE_ACCESSED;
 1289 
 1290         return error;
 1291 }
 1292 
 1293 /* --------------------------------------------------------------------- */
 1294 
 1295 static int
 1296 tmpfs_inactive(struct vop_inactive_args *v)
 1297 {
 1298         struct vnode *vp = v->a_vp;
 1299         struct thread *l = v->a_td;
 1300 
 1301         struct tmpfs_node *node;
 1302 
 1303         MPASS(VOP_ISLOCKED(vp, l));
 1304 
 1305         node = VP_TO_TMPFS_NODE(vp);
 1306 
 1307         if (node->tn_links == 0)
 1308                 vrecycle(vp, l);
 1309 
 1310         return 0;
 1311 }
 1312 
 1313 /* --------------------------------------------------------------------- */
 1314 
 1315 int
 1316 tmpfs_reclaim(struct vop_reclaim_args *v)
 1317 {
 1318         struct vnode *vp = v->a_vp;
 1319 
 1320         struct tmpfs_mount *tmp;
 1321         struct tmpfs_node *node;
 1322 
 1323         node = VP_TO_TMPFS_NODE(vp);
 1324         tmp = VFS_TO_TMPFS(vp->v_mount);
 1325 
 1326         vnode_destroy_vobject(vp);
 1327         cache_purge(vp);
 1328         tmpfs_free_vp(vp);
 1329 
 1330         /* If the node referenced by this vnode was deleted by the user,
 1331          * we must free its associated data structures (now that the vnode
 1332          * is being reclaimed). */
 1333         if (node->tn_links == 0)
 1334                 tmpfs_free_node(tmp, node);
 1335 
 1336         MPASS(vp->v_data == NULL);
 1337         return 0;
 1338 }
 1339 
 1340 /* --------------------------------------------------------------------- */
 1341 
 1342 static int
 1343 tmpfs_print(struct vop_print_args *v)
 1344 {
 1345         struct vnode *vp = v->a_vp;
 1346 
 1347         struct tmpfs_node *node;
 1348 
 1349         node = VP_TO_TMPFS_NODE(vp);
 1350 
 1351         printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
 1352             node, node->tn_flags, node->tn_links);
 1353         printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX
 1354             ", status 0x%x\n",
 1355             node->tn_mode, node->tn_uid, node->tn_gid,
 1356             (uintmax_t)node->tn_size, node->tn_status);
 1357 
 1358         if (vp->v_type == VFIFO)
 1359                 fifo_printinfo(vp);
 1360 
 1361         printf("\n");
 1362 
 1363         return 0;
 1364 }
 1365 
 1366 /* --------------------------------------------------------------------- */
 1367 
 1368 static int
 1369 tmpfs_pathconf(struct vop_pathconf_args *v)
 1370 {
 1371         int name = v->a_name;
 1372         register_t *retval = v->a_retval;
 1373 
 1374         int error;
 1375 
 1376         error = 0;
 1377 
 1378         switch (name) {
 1379         case _PC_LINK_MAX:
 1380                 *retval = LINK_MAX;
 1381                 break;
 1382 
 1383         case _PC_NAME_MAX:
 1384                 *retval = NAME_MAX;
 1385                 break;
 1386 
 1387         case _PC_PATH_MAX:
 1388                 *retval = PATH_MAX;
 1389                 break;
 1390 
 1391         case _PC_PIPE_BUF:
 1392                 *retval = PIPE_BUF;
 1393                 break;
 1394 
 1395         case _PC_CHOWN_RESTRICTED:
 1396                 *retval = 1;
 1397                 break;
 1398 
 1399         case _PC_NO_TRUNC:
 1400                 *retval = 1;
 1401                 break;
 1402 
 1403         case _PC_SYNC_IO:
 1404                 *retval = 1;
 1405                 break;
 1406 
 1407         case _PC_FILESIZEBITS:
 1408                 *retval = 0; /* XXX Don't know which value should I return. */
 1409                 break;
 1410 
 1411         default:
 1412                 error = EINVAL;
 1413         }
 1414 
 1415         return error;
 1416 }
 1417 
 1418 static int
 1419 tmpfs_vptofh(struct vop_vptofh_args *ap)
 1420 {
 1421         struct tmpfs_fid *tfhp;
 1422         struct tmpfs_node *node;
 1423 
 1424         tfhp = (struct tmpfs_fid *)ap->a_fhp;
 1425         node = VP_TO_TMPFS_NODE(ap->a_vp);
 1426 
 1427         tfhp->tf_len = sizeof(struct tmpfs_fid);
 1428         tfhp->tf_id = node->tn_id;
 1429         tfhp->tf_gen = node->tn_gen;
 1430 
 1431         return (0);
 1432 }
 1433 
 1434 /* --------------------------------------------------------------------- */
 1435 
 1436 /*
 1437  * vnode operations vector used for files stored in a tmpfs file system.
 1438  */
 1439 struct vop_vector tmpfs_vnodeop_entries = {
 1440         .vop_default =                  &default_vnodeops,
 1441         .vop_lookup =                   vfs_cache_lookup,
 1442         .vop_cachedlookup =             tmpfs_lookup,
 1443         .vop_create =                   tmpfs_create,
 1444         .vop_mknod =                    tmpfs_mknod,
 1445         .vop_open =                     tmpfs_open,
 1446         .vop_close =                    tmpfs_close,
 1447         .vop_access =                   tmpfs_access,
 1448         .vop_getattr =                  tmpfs_getattr,
 1449         .vop_setattr =                  tmpfs_setattr,
 1450         .vop_read =                     tmpfs_read,
 1451         .vop_write =                    tmpfs_write,
 1452         .vop_fsync =                    tmpfs_fsync,
 1453         .vop_remove =                   tmpfs_remove,
 1454         .vop_link =                     tmpfs_link,
 1455         .vop_rename =                   tmpfs_rename,
 1456         .vop_mkdir =                    tmpfs_mkdir,
 1457         .vop_rmdir =                    tmpfs_rmdir,
 1458         .vop_symlink =                  tmpfs_symlink,
 1459         .vop_readdir =                  tmpfs_readdir,
 1460         .vop_readlink =                 tmpfs_readlink,
 1461         .vop_inactive =                 tmpfs_inactive,
 1462         .vop_reclaim =                  tmpfs_reclaim,
 1463         .vop_print =                    tmpfs_print,
 1464         .vop_pathconf =                 tmpfs_pathconf,
 1465         .vop_vptofh =                   tmpfs_vptofh,
 1466         .vop_bmap =                     VOP_EOPNOTSUPP,
 1467 };
 1468 

Cache object: 7b83aa208b311e6eb1b96ee799d3541d


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